As the name suggets, NamedBinaryTagParser is an NBT parser (& now also a serializer), written in Go.
It supports all tag types, as well as being able to intelligently detect and handle gzip & zlib compression (or no compression).
NamedBinaryTagParser's tag ID constants can be found here.
NamedBinaryTagParser's tag types can be found here.
func example(reader io.Reader) {
	// create our parser instance
	// takes an io.Reader
	parser, err := nbt.NewParser(reader)
	if err != nil {
		panic(err)
	}
	// the Parser.Read() function will completely parse the NBT compound provided from the reader
	// it returns the parsed NBT compound, which is a type alias of map[string]nbt.Tag,
	// the name of the outer NBT compound, and also the error if one occurred.
	compound, name, err := parser.Read()
	if err != nil {
		panic(err)
	}
	// say in our compound we have a Long tag called "my_long"
	myTag := compound["my_long"] // this returns the generic tag
	// we can verify that the tag is a long
	if myTag.Type() != nbt.TagTypeLong {
		panic("tag is not a long")
	}
	// we can now safely cast to a nbt.TagLong, which is a type alias for int64
	myLong := myTag.(nbt.TagLong)
	fmt.Println(myLong)
}func example(reader io.Reader) {
	// create our parser instance
	parser, err := nbt.NewParser(reader)
	if err != nil {
		panic(err)
	}
	// read the NBT compound
	compound, name, err := parser.Read()
	if err != nil {
		panic(err)
	}
	// say this time we have a list of compounds, where the list is called "my_list"
	myTag := compound["my_list"] // this returns the generic tag
	// we can verify that the tag is a list
	if myTag.Type() != nbt.TagTypeList {
		panic("tag is not a list")
	}
	// cast to nbt.TagList
	myList := myTag.(nbt.TagList)
	// verify that the elements are compounds
	if myList.ElementType != nbt.TagTypeCompound {
		panic("elements are not compounds")
	}
	// myList.Elements is a []nbt.Tag
	for _, tag := range myList.Elements {
		// we have verified that they are compounds already, so we can cast without further checks
		compound := tag.(nbt.TagCompound)
		// we can treat the compound like normal now
		// for example, i'll retrieve a string called "my_string"
		myString, ok := compound["my_string"].(nbt.TagString)
		if !ok {
			panic("my_string was not a string")
		}
		fmt.Println(myString)
	}
}A small example in which we serialize an NBT compound to a JSON object.
func example(r io.Reader) {
	parser, err := nbt.NewParser(r)
	if err != nil {
		panic(err)
	}
	tag, name, err := parser.Read()
	if err != nil {
		panic(err)
	}
	withName := map[string]interface{}{
		name: tag,
	}
	marshalled, err := json.Marshal(withName)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(marshalled))
}JSON output
```
{
	"Level": {
		"byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))": "",
		"byteTest": 127,
		"doubleTest": 0.4931287132182315,
		"floatTest": 0.49823147,
		"intTest": 2147483647,
		"listTest (compound)": {
			"ElementType": 10,
			"Elements": [{
				"created-on": 1264099775885,
				"name": "Compound tag #0"
			}, {
				"created-on": 1264099775885,
				"name": "Compound tag #1"
			}]
		},
		"listTest (long)": {
			"ElementType": 4,
			"Elements": [11, 12, 13, 14, 15]
		},
		"longTest": 9223372036854775807,
		"nested compound test": {
			"egg": {
				"name": "Eggbert",
				"value": 0.5
			},
			"ham": {
				"name": "Hampus",
				"value": 0.75
			}
		},
		"shortTest": 32767,
		"stringTest": "HELLO WORLD THIS IS A TEST STRING ÅÄÖ!"
	}
}
```
When serializing data, if you wish to use compression, you should parse a gzip writer or zlib writer to NamedBinaryTagParser, unlike when parsing data, in which NamedBinaryTagParser automatically detects the compression and applies the correct reader.
func example(w io.Writer) {
	// your data set
	// this is wiki.vg's bigtest.nbt
	data := nbt.TagCompound{
		"nested compound test": nbt.TagCompound{
			"egg": nbt.TagCompound{
				"name":  nbt.TagString("Eggbert"),
				"value": nbt.TagFloat(0.5),
			},
			"ham": nbt.TagCompound{
				"name":  nbt.TagString("Hampus"),
				"value": nbt.TagFloat(0.75),
			},
		},
		"intTest":    nbt.TagInt(2147483647),
		"byteTest":   nbt.TagByte(127),
		"stringTest": nbt.TagString("HELLO WORLD THIS IS A TEST STRING \xc3\x85\xc3\x84\xc3\x96!"),
		"listTest (long)": nbt.TagList{
			ElementType: nbt.TagTypeLong,
			Elements: []nbt.Tag{
				nbt.TagLong(11),
				nbt.TagLong(12),
				nbt.TagLong(13),
				nbt.TagLong(14),
				nbt.TagLong(15),
			},
		},
		"doubleTest": nbt.TagDouble(0.49312871321823148),
		"floatTest":  nbt.TagFloat(0.49823147058486938),
		"longTest":   nbt.TagLong(9223372036854775807),
		"listTest (compound)": nbt.TagList{
			ElementType: nbt.TagTypeCompound,
			Elements: []nbt.Tag{
				nbt.TagCompound{
					"created-on": nbt.TagLong(1264099775885),
					"name":       nbt.TagString("Compound tag #0"),
				},
				nbt.TagCompound{
					"created-on": nbt.TagLong(1264099775885),
					"name":       nbt.TagString("Compound tag #1"),
				},
			},
		},
		"byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))": nbt.TagByteArray(byteArrayTestData),
		"shortTest": nbt.TagShort(32767),
	}
	// create out writer
	writer := nbt.NewWriter(w)
	outerName := "Level" // this is the name of the outer NBT compound
	if err := writer.Write(data, outerName); err != nil {
		panic(err)
	}
}I have written a test based on wiki.vg's bigtest.nbt. You can run the test with
go test ./testI have also written a benchmark based on wiki.vg's bigtest.nbt. You can run the benchmark with
go test ./test -bench .Running the benchmark on my home PC (R5 3600X, 12GB RAM), I achieved the following results:
$ go test ./test -bench .
goos: linux
goarch: amd64
pkg: github.com/RyanW02/NamedBinaryTagParser/test
BenchmarkParse-12          53491             21447 ns/op
BenchmarkWrite-12         204349              5781 ns/op
PASS
ok      github.com/RyanW02/NamedBinaryTagParser/test    8.542s- More tests