No reflection
Fields are described with a fluent builder and generics. The compiler knows every type at build time; the runtime never inspects one.
Parco is a binary serializer built on generics: no reflection, no codegen, no struct tags, zero core dependencies. You describe the layout with a builder; parco reads and writes exactly those bytes.
The honest part: it's schema-driven, like Protobuf and unlike JSON. Both ends must agree on the layout beforehand. That trade is where the speed comes from — not benchmark tricks.
Fields are described with a fluent builder and generics. The compiler knows every type at build time; the runtime never inspects one.
Primitives, slices, maps, arrays, nested structs, optionals. Build a type once, reuse it anywhere — standalone or inside another builder.
Register models under a type ID and parse or compile mixed messages from one reader — or use the global registry.
Choose byte order per field and header width per collection: a UInt8Header costs one byte for up to 255 elements.
Pooled buffers on the hot path, hardened against lying length headers: memory grows with data that actually arrives.
The core API is stdlib only. No runtime library, no generated files to keep in sync, nothing to version but your own code.
type Point struct { X, Y int32 } factory := parco.ObjectFactory[Point]() parser, compiler := parco.Builder[Point](factory). Int32(binary.LittleEndian, func(p *Point) int32 { return p.X }, func(p *Point, x int32) { p.X = x }, ). Int32(binary.LittleEndian, func(p *Point) int32 { return p.Y }, func(p *Point, y int32) { p.Y = y }, ). Parco() var buf bytes.Buffer err := compiler.Compile(Point{X: 1, Y: 2}, &buf) // 8 bytes on the wire point, err := parser.Parse(&buf) // {1 2}
parser + compiler = parco
Two halves, same builder: every model you describe yields its parser and its compiler from one definition.
Parco is Go-only and will stay that way. If Protobuf already works for you, keep it.
| benchmark | ns/op | B/op | allocs/op |
|---|
Headline numbers from the reference suite (see PERFORMANCE.md for methodology and honest caveats):
| vs | speed | payload size | allocations |
|---|---|---|---|
| encoding/json | 2–3× faster | ~70% smaller | ~10× fewer |
| msgpack | comparable | ~40% smaller | fewer |
Continuous results land on the benchmark dashboard after each push to main.