Glint brings binary serialization performance to Go without the complexity. Encode and decode your existing structs at speeds that match or exceed code-generated solutions.
|
Encoding (ns/op) |
Decoding (ns/op) |
Key Benefits
|
See detailed benchmarks for comprehensive performance data.
import "github.com/kungfusheep/glint"
// Define your struct - no special annotations required
type Person struct {
Name string `glint:"name"`
Age int `glint:"age"`
}
// Create encoder/decoder once, reuse many times
var (
encoder = glint.NewEncoder[Person]()
decoder = glint.NewDecoder[Person]()
)
// Encode
buffer := glint.NewBufferFromPool()
defer buffer.ReturnToPool()
encoder.Marshal(&Person{Name: "Alice", Age: 30}, buffer)
// Decode
var person Person
err := decoder.Unmarshal(buffer.Bytes, &person)- Sub-microsecond operations: As low as 60ns for simple structs
- Zero allocations: Careful design eliminates heap allocations
- Compact format: 70% smaller than JSON, 40% smaller than Protobuf
- No code generation: Work directly with your Go structs
- No schema files: Self-describing format includes schemas
- Simple API: Familiar Marshal/Unmarshal pattern
- Backward compatibility: Add fields freely, remove fields safely
- Forward compatibility: Older versions ignore unknown fields
- Type safety: Schema validation ensures type compatibility
- Memory protection: Configurable limits prevent DoS attacks
Glint's compatibility strategy is simple and powerful:
- โ Add new fields - Older versions ignore them automatically
- โ Remove fields - Newer versions handle missing fields gracefully
- โ Change field types - The only breaking change (schema mismatch)
This approach gives you flexibility to evolve schemas naturally:
// Version 1
type User struct {
ID string `glint:"id"`
Name string `glint:"name"`
}
// Version 2 - Safe to deploy alongside v1
type User struct {
ID string `glint:"id"`
Name string `glint:"name"`
Email string `glint:"email"` // New field - ignored by v1
Created time.Time `glint:"created"` // New field - ignored by v1
// Age int `glint:"age"` // Removed - v2 handles absence
}No version numbers, no migration scripts - just natural schema evolution.
go get github.com/kungfusheep/glintGlint works with standard Go types out of the box:
- Basic types: int/8/16/32/64, uint/8/16/32/64, float32/64, string, bool, time.Time
- Composite types: structs, slices, maps
- Pointers: Automatic nil handling
- Custom types: Via
MarshalBinary/UnmarshalBinaryinterfaces
Glint provides configurable limits to prevent malicious inputs from exhausting memory:
// Custom limits for untrusted data
decoder := glint.NewDecoderWithLimits[MyStruct](glint.DecodeLimits{
MaxByteSliceLen: 10 * 1024 * 1024, // 10MB
MaxStringLen: 1 * 1024 * 1024, // 1MB
})Control field encoding with struct tags:
type User struct {
ID string `glint:"id"`
Secret string // Skip this field
Data []byte `glint:"data,copy"` // Copy bytes instead of referencing
CreatedAt time.Time `glint:"created_at"`
}Implement custom encoding for your types:
type UUID [16]byte
func (u UUID) MarshalBinary() []byte {
return u[:]
}
func (u *UUID) UnmarshalBinary(data []byte) {
copy(u[:], data)
}
type User struct {
ID UUID `glint:"id,encoder"` // Uses custom encoding
}For high-frequency communication between services, skip schema transmission:
// Server side - get trust header after first decode
trustHeader := glint.NewTrustHeader(decoder.impl)
response.Header.Set(trustHeader.Key(), trustHeader.Value())
// Client side - use trusted encoding
trustee := glint.HTTPTrustee(request)
buffer := glint.NewBufferWithTrust(trustee, encoder.impl)
encoder.Marshal(&data, buffer) // Smaller payload, no schemaFor dynamic document construction without structs:
doc := &glint.DocumentBuilder{}
doc.AppendString("name", "Alice").
AppendInt("age", 30).
AppendSlice("tags", glint.SliceBuilder{}.
AppendStringSlice([]string{"admin", "user"}))
data := doc.Bytes()Inspect Glint documents without decoding:
// Pretty print any Glint document
glint.Print(encodedData)
// Use with fmt for different formats
doc := glint.Document(encodedData)
fmt.Printf("%s", doc) // Tree view
fmt.Printf("%+v", doc) // Tree + hex
fmt.Printf("%x", doc) // Raw hexGlint includes a powerful CLI for working with binary data:
go install github.com/kungfusheep/glint/cmd/glint@latest
# Inspect binary files
cat mydata.glint | glint
# Decode API responses
curl -s https://api.example.com/user | glint
# Extract specific fields
cat mydata.glint | glint get user.name
# Generate Go structs from data
cat mydata.glint | glint generate go package.StructNameSee the CLI documentation for more features.
Glint excels in scenarios where:
- Performance matters: High-throughput services, real-time systems
- Schema flexibility is needed: Microservices with independent deployment
- Storage is constrained: IoT devices, embedded systems, high-volume logging
- Go-native solution preferred: No code generation
See LICENSE for details.