Skip to content

colinc86/coding

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Package coding

Go Tests Go Reference

Package coding contains structures for encoding and decoding values.

Installing

Navigate to your module and execute the following.

$ go get github.com/colinc86/coding

Using

Import the package:

import "github.com/colinc86/coding"

Encoding Data

The Encoder type is responsible for encoding values.

Creating an Encoder

Calling NewEncoder creates a new encoder with an empty internal buffer.

e := coding.NewEncoder()

Encoding

The Encoder type supports encoding:

  • bool
  • int, int64, int32, int16, int8
  • uint, uint64, uint32, uint16, uint8
  • float64, float32
  • string
  • []byte

The order that you encode values is the order that they must be decoded with a Decoder.

e.EncodeBool(true)
e.EncodeString("Hello, World!")
e.EncodeInt(42)

d, err := json.Marshal(someStruct)
e.EncodeData(d)

Flushing Data

If you need to start over, you can call Flush on the encoder to clear its internal buffer.

e.Flush()

Getting Encoded Data

Use the Data function to get the encoder's encoded data. This method calculates the encoded data's CRC32 and appends the bytes to the end of the encoded data before returning it so it may be verified by a decoder.

encodedData := e.Data()

Compressing

You can, optionally, call the Compress function which will return a compressed version of the data returned by calling Data on the encoder.

compressedData, err := e.Compress()

Decoding

The Decoder type is responsible for decoding values.

Creating a Decoder

Call NewDecoder and give it the data to decode.

d := NewDecoder(compressedData)

Decompressing

If you obtained data from an encoder by calling Compress, then the first method you must call on the decoder is Decompress. Otherwise, this step is unnecessary and will return an error.

Calling Decompress decompresses the decoder's internal buffer so there is no need to keep track of new slices.

err := d.Decompress()

Validating Data

It is advised that you validate the decoder's data. Validating checks the CRC bytes that were appened to the encoder's data when calling Data.

if err := d.Validate; err != nil {
	fmt.Printf("Invalid data: %s\n", err)
}

Decoding Data

The Decoder type supports decoding all of the same types as encoders. As mentioned above, you must decode values in the order they were decoded.

// You should catch errors, but for the sake of brevity...
boolValue, _ := d.DecodeBool()
stringValue, _ := d.DecodeString()
intValue, _ := d.DecodeInt()
jsonData, _ := d.DecodeData()

someStruct = new(SomeStruct)
_ := json.Unmarshal(jsonData, someStruct)

Example

package main

import (
	"fmt"

	"github.com/colinc86/coding"
)

func main() {
	e := coding.NewEncoder()
	e.EncodeString("{ \"name\": \"pi\" }")
	e.EncodeFloat64(math.Pi)
	e.EncodeString("{ \"name\": \"phi\" }")
	e.EncodeFloat64(math.Phi)
	e.EncodeString("{ \"name\": \"e\" }")
	e.EncodeFloat64(math.E)
	e.EncodeString("{ \"name\": \"ln(2)\" }")
	e.EncodeFloat64(math.Ln2)

	fmt.Printf("Bytes: %d\n", len(e.Data()))

	cd, err := e.Compress()
	if err != nil {
		fmt.Printf("Error compressing data: %s\n", err)
		return
	}

	fmt.Printf("Compressed bytes: %d\n", len(cd))
	fmt.Printf("Change: %0.f%%\n", 100.0*float64(len(cd)-len(e.data))/float64(len(e.data)))

	d := coding.NewDecoder(cd)
	if err = d.Decompress(); err != nil {
		fmt.Printf("Error decompressing data: %s\n", err)
		return
	}

	if err = d.Validate(); err != nil {
		fmt.Printf("Error validating data: %s\n", err)
		return
	}

	var s string
	if s, err = d.DecodeString(); err != nil {
		fmt.Printf("Error decoding string: %s\n", err)
		return
	}
	fmt.Printf("String: %s\n", s)

	var f float64
	if f, err = d.DecodeFloat64(); err != nil {
		fmt.Printf("Error decoding float: %s\n", err)
		return
	}
	fmt.Printf("Float: %f\n", f)
}

Output:

Bytes: 153
Compressed bytes: 106
Change: -28%
String: { "name": "pi" }
Float: 3.141593