Tiny binary serializer and deserializer to create on demand parsers and compilers

Overview

Parco

Hobbyist binary compiler and parser built with as less reflection as possible, highly extensible and with zero dependencies.

There are plenty packages over the internet which work by leveraging the power of struct tags and reflection. While sometimes that can be convenient for some scenarios, that approach leaves little room to define and register custom types in addition to have an appositive effect on performance.

Do note:

  • unsafe is employed (quite isolated though).
  • To avoid reflection, adapters are provided in order to iterate through to slices.

Usage

So the most complete usage would look like this

Parser + compiler

package main

import (
    "bytes"
    types "github.com/sonirico/parco/internal"
    parco "github.com/sonirico/parco/pkg"
    "log"
)

type Example struct {
    Greet     string
    LifeSense int
    Grades    []uint8
}

func getGreet(x interface{}) interface{} {
    return x.(Example).Greet
}

func getLifeSense(x interface{}) interface{} {
    return x.(Example).LifeSense
}

func getGrades(x interface{}) interface{} {
    return types.UInt8Iter(x.(Example).Grades)
}

func main() {
    parser, compiler := parco.NewBuilder().
        FieldGet("greet", types.SmallVarchar(), getGreet).
        FieldGet("life_sense", types.UInt8(), getLifeSense).
        FieldGet("grades", types.Array(2, types.UInt8(), types.UInt8()), getGrades).
        ParCo()

    ex := Example{
        Greet:     "hey",
        LifeSense: 42,
        Grades:    []uint8{5, 6},
    }

    output := bytes.NewBuffer(nil)
    if err := compiler.Compile(ex, output); err != nil {
        log.Fatal(err)
    }

    raw := output.Bytes()
    log.Println("raw bytes", raw)

    result, err := parser.ParseBytes(raw)
    if err != nil {
        log.Fatal(err)
    }

    greet, _ := result.GetString("greet")
    lifeSense, _ := result.GetUint8("life_sense")
    grades, _ := result.GetArray("grades")

    log.Println("greet", greet)
    log.Println("life sense", lifeSense)
    log.Println("total grades", grades.Len())

    grades.Range(func(value types.Value) {
        log.Println("grade", value.GetUInt8())
    })
}

However, both parser and compiler can be used independently.

Parser

raw := []byte{4, 72, 79, 76, 65, 42, 9, 10}

parser := parco.NewBuilder().
    Field("greet", types.SmallVarchar()).
    Field("life_sense", types.UInt8()).
    Field("grades", types.Array(2, types.UInt8(), types.UInt8())).
    Parser()


result, err := parser.ParseBytes(raw)

if err != nil {
    log.Fatal(err)
}

greet, _ := result.GetString("greet")
lifeSense, _ := result.GetUInt8("life_sense")
grades, _ := result.GetArray("grades")

log.Println("greet", greet)
log.Println("life sense", lifeSense)
log.Println("total grades", grades.Len())

grades.Range(func(value types.Value) {
    log.Println("grade", value.GetUInt8())
})

Compiler

type Example struct {
    Greet     string
    LifeSense int
    Grades    []uint8
}

func getGreet(x interface{}) interface{} {
    return x.(Example).Greet
}

func getLifeSense(x interface{}) interface{} {
    return x.(Example).LifeSense
}

func getGrades(x interface{}) interface{} {
    return types.Uint8Iter(x.(Example).Grades)
}

func main() {
    compiler := parco.NewBuilder().
        FieldGet("greet", types.SmallVarchar(), getGreet).
        FieldGet("life_sense", types.UInt8(), getLifeSense).
        FieldGet("grades", types.Array(2, types.UInt8(), types.UInt8()), getGrades).
        Compiler()

    ex := Example{
        Greet:     "hey",
        LifeSense: 42,
        Grades:    []uint8{5, 6},
    }

    output := bytes.NewBuffer(nil)
    if err := compiler.Compile(ex, output); err != nil {
        log.Fatal(err)
    }
    log.Println(output.Bytes())
}

For fully functional examples showing the whole API, refer to Examples.

Benchmarks

goos: linux
goarch: amd64

pkg: github.com/sonirico/parco/pkg

cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz

BenchmarkParco_Compile/small_size-12         	1000000000	         0.0000032 ns/op	        35.00 bytes/op	       0 B/op	       0 allocs/op
BenchmarkParco_Compile/medium_size-12        	1000000000	         0.0000082 ns/op	       325.0 bytes/op	       0 B/op	       0 allocs/op
BenchmarkParco_Compile/large_size-12         	1000000000	         0.0000470 ns/op	      3206 bytes/op	       0 B/op	       0 allocs/op

BenchmarkJson_Compile/small_size-12          	1000000000	         0.0000052 ns/op	       116.0 bytes/op	       0 B/op	       0 allocs/op
BenchmarkJson_Compile/medium_size-12         	1000000000	         0.0000207 ns/op	       756.0 bytes/op	       0 B/op	       0 allocs/op
BenchmarkJson_Compile/large_size-12          	1000000000	         0.0000629 ns/op	      7071 bytes/op	       0 B/op	       0 allocs/op

PASS
ok  	github.com/sonirico/parco/pkg	0.010s

TODO

  • Support for all primitive types: boolean, nil...
  • Extend interface to include version
  • Static code generation
  • Replace encoding/binary usage by faster implementations
  • Support for nested schema definition
Owner
Marquitos
🇪🇸 你喜欢我的裤子吗 🇨🇳
Marquitos
A tiny command-line orientated PKM tool inspired by Taskwarrior and daily logging.

eden eden is a command line tool for creating and manipulating daily log notes. It started life as a series of different bash script that did various

null 0 Jan 20, 2022
A tiny "sandbox" to run untrusted code 🏖️

Sandy A tiny sandbox to run untrusted code. ??️ Sandy uses Ptrace to hook into READ syscalls, giving you the option to accept or deny syscalls before

Craig Mulligan 338 Jan 4, 2022
A tiny markup language for terminal output. Makes formatting output in CLI apps easier!

tml - Terminal Markup Language A Go module (and standalone binary) to make the output of coloured/formatted text in the terminal easier and more reada

Liam Galvin 683 May 9, 2022
A tiny git forge written in Go

Smithy smithy (n) A blacksmith's shop; a forge. Smithy is a web frontend for git repositories. It's implemented entirely in Golang, compiles to a sing

Honza Pokorny 203 May 1, 2022
A tiny Nano wallet, focused on ease of use through simplicity

atto is a tiny Nano wallet, which focuses on ease of use through simplicity. Disclaimer: I am no cryptographer and atto has not been audited. I cannot

Richard Ulmer 31 Apr 27, 2022
A tiny Go library + client for downloading Youtube videos. The library is capable of fetching Youtube video metadata, in addition to downloading videos.

A tiny Go library + client (command line Youtube video downloader) for downloading Youtube videos. The library is capable of fetching Youtube video metadata, in addition to downloading videos. If ffmpeg is available, client can extract MP3 audio from downloaded video files.

Kunal Diwan 3 Apr 30, 2022
A tiny cli command/daemon for syncing toggl time entries with Jira

toggl-sync A tiny cli command/daemon for syncing toggl time entries with Jira Installation Install the app via brew package manager. brew tap timemate

TimeMate 2 Nov 30, 2021
You-Get is a tiny command-line utility to download media contents (videos, audios, images) from the Web,

You-Get NOTICE: Read this if you are looking for the conventional "Issues" tab. You-Get is a tiny command-line utility to download media contents (vid

Mort Yao 44k May 15, 2022
minigli is a tiny command argument parser for Go.

minigli is a tiny command argument parser for Go.

hitoshi44 0 Jan 29, 2022
archy is an static binary to determine current kernel and machine architecture, with backwards compatible flags to uname, and offers alternative output format of Go runtime (i.e. GOOS, GOARCH).

archy archy is an simple binary to determine current kernel and machine architecture, which wraps uname and alternatively can read from Go runtime std

xargs-dev 3 Mar 18, 2022
Run your MapReduce workloads as a single binary on a single machine with multiple CPUs and high memory. Pricing of a lot of small machines vs heavy machines is the same on most cloud providers.

gomap Run your MapReduce workloads as a single binary on a single machine with multiple CPUs and high memory. Pricing of a lot of small machines vs he

null 20 May 1, 2022
Gostall - Run go install ./cmd/server and not have the binary install in your GOBIN be called server?

GOSTALL Ever wanted to run go install ./cmd/server and not have the binary insta

David Desmarais-Michaud 0 Jan 7, 2022
gif effects CLI. single binary, no dependencies. linux, osx, windows.

yeetgif Composable GIF effects CLI, with reasonable defaults. Made for custom Slack/Discord emoji :) Get it Alternative 1: go get Alternative 2: just

Sergey Grebenshchikov 519 May 6, 2022
elf binary parsing utility written in Go.

What is it ? go-readelf is a small elf binary parser currently capable of printing relocation entries, elf header, sections and Symbols. It utilizes G

null 50 May 12, 2022
Another Go shellcode loader designed to work with Cobalt Strike raw binary payload.

Bankai Another Go shellcode loader designed to work with Cobalt Strike raw binary payload. I created this project to mainly educate myself learning Go

bigb0ss 110 Apr 26, 2022
A lightweight replacement for the standard fmt package, reduces binary size by roughly 400kb in a hello world

console This is a lightweight replacement for the fmt package, reduces the binary size by roughly 400kb in a hello world program. Please note: This pa

null 1 Nov 7, 2021
Instal - Install any binary app from a script URL

??️ Install any binary app from a script URL. this cli app is an alternative to

Abdfn 13 Apr 24, 2022
null 0 Jan 27, 2022
Small, fast library to create ANSI colored strings and codes. [go, golang]

ansi Package ansi is a small, fast library to create ANSI colored strings and codes. Install Get it go get -u github.com/mgutz/ansi Example import "gi

Mario Gutierrez 362 Apr 23, 2022