<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pavan Kumar</title>
    <description>The latest articles on DEV Community by Pavan Kumar (@sshprotocol).</description>
    <link>https://dev.to/sshprotocol</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3832939%2F262b8e12-d4e6-43f4-baa8-97bde6574466.jpg</url>
      <title>DEV Community: Pavan Kumar</title>
      <link>https://dev.to/sshprotocol</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sshprotocol"/>
    <language>en</language>
    <item>
      <title>I built a Go library to solve a problem Python solved in 2002</title>
      <dc:creator>Pavan Kumar</dc:creator>
      <pubDate>Sun, 22 Mar 2026 02:38:24 +0000</pubDate>
      <link>https://dev.to/sshprotocol/i-built-a-go-library-to-solve-a-problem-python-solved-in-2002-4n06</link>
      <guid>https://dev.to/sshprotocol/i-built-a-go-library-to-solve-a-problem-python-solved-in-2002-4n06</guid>
      <description>&lt;p&gt;I want to preface this by saying this is not a "look what I built" &lt;br&gt;
post. This is more of a "I kept hitting the same wall and eventually &lt;br&gt;
decided to do something about it" post.&lt;/p&gt;
&lt;h2&gt;
  
  
  How it started
&lt;/h2&gt;

&lt;p&gt;I was playing Path of Exile 2 a few weeks back and noticed some &lt;br&gt;
obvious desync — my character position on my screen not matching &lt;br&gt;
what the server thought. Classic multiplayer networking bug. &lt;br&gt;
I did not think much of it at the time.&lt;/p&gt;

&lt;p&gt;Then I hit a similar issue using a Go based VPN app I run on my &lt;br&gt;
own infrastructure. Sessions dropping silently under load. &lt;br&gt;
No obvious error. Just wrong behaviour.&lt;/p&gt;

&lt;p&gt;Then the same class of bug showed up in a Go project I was &lt;br&gt;
building at work. I was parsing tightly packed UDP binary packets &lt;br&gt;
and somewhere in my manual bit shifting code I had an offset wrong. &lt;br&gt;
One bit. Everything downstream was garbage.&lt;/p&gt;

&lt;p&gt;Three times. Three different contexts. Same root cause.&lt;/p&gt;

&lt;p&gt;At that point I stopped and actually looked for a proper solution.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I found
&lt;/h2&gt;

&lt;p&gt;Python developers have had &lt;br&gt;
&lt;a href="https://construct.readthedocs.io" rel="noopener noreferrer"&gt;construct&lt;/a&gt; since 2002. &lt;br&gt;
You define your packet schema declaratively — field name, &lt;br&gt;
type, bit width — and the library handles everything. &lt;br&gt;
No bit math. No manual shifting. Used in production &lt;br&gt;
by the Python network engineering community for over &lt;br&gt;
two decades. It is the gold standard for this problem.&lt;/p&gt;

&lt;p&gt;Go has nothing like it.&lt;/p&gt;

&lt;p&gt;That is not an accident. Go's designers deliberately left &lt;br&gt;
bitfields out of the language. C has native bitfields &lt;br&gt;
but the C standard never defined which direction bits &lt;br&gt;
are ordered in memory — every compiler decides for itself. &lt;br&gt;
Go wanted no part of that ambiguity.&lt;/p&gt;

&lt;p&gt;In 2019 someone filed a formal proposal — &lt;br&gt;
&lt;a href="https://github.com/golang/go/issues/29650" rel="noopener noreferrer"&gt;golang/go#29650&lt;/a&gt; &lt;br&gt;
— requesting native bit and byte allocation in structs. &lt;br&gt;
It was closed without action, labelled &lt;code&gt;FrozenDueToAge&lt;/code&gt;. &lt;br&gt;
The Go team's position is clear — this belongs in &lt;br&gt;
a library, not the language.&lt;/p&gt;

&lt;p&gt;So I looked for the library.&lt;/p&gt;

&lt;p&gt;Three packages exist in the Go ecosystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;jmatsuzawa/go-bitfield&lt;/code&gt; — Unmarshal only. 
Zero stars. Marshal listed as a TODO in their own README.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;encodingx/binary&lt;/code&gt; — Has both Marshal and Unmarshal 
but requires wrapping every struct in nested word-structs. 
Awkward API, not idiomatic Go.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Velocidex/vtypes&lt;/code&gt; — A forensics tool driven by JSON profiles. 
Not designed for production network code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of them have Validate, Explain, or Diff. &lt;br&gt;
All effectively abandoned.&lt;/p&gt;

&lt;p&gt;That was the gap. I decided to fill it.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;I called it &lt;strong&gt;nibble&lt;/strong&gt; — a nibble is 4 bits, half a byte. &lt;br&gt;
Felt right for a library that works at the bit level.&lt;/p&gt;

&lt;p&gt;The idea is simple. Python's construct lets you describe &lt;br&gt;
a binary protocol in plain readable code and the library &lt;br&gt;
does all the bit math for you. nibble brings that same &lt;br&gt;
philosophy to Go using something Go developers already &lt;br&gt;
know — struct tags.&lt;/p&gt;

&lt;p&gt;The same pattern you use for JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"name"`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;nibble uses the same convention:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;Health&lt;/span&gt; &lt;span class="kt"&gt;uint16&lt;/span&gt; &lt;span class="s"&gt;`bits:"9"`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You define your packet schema once as a struct. &lt;br&gt;
Every field gets a &lt;code&gt;bits&lt;/code&gt; tag telling nibble exactly &lt;br&gt;
how wide that field is on the wire. That single &lt;br&gt;
definition drives everything.&lt;/p&gt;

&lt;p&gt;Here is a real game packet example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;GamePacket&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;IsAlive&lt;/span&gt;   &lt;span class="kt"&gt;bool&lt;/span&gt;   &lt;span class="s"&gt;`bits:"1"`&lt;/span&gt;  &lt;span class="c"&gt;// 1 bit  — true or false&lt;/span&gt;
    &lt;span class="n"&gt;WeaponID&lt;/span&gt;  &lt;span class="kt"&gt;uint8&lt;/span&gt;  &lt;span class="s"&gt;`bits:"4"`&lt;/span&gt;  &lt;span class="c"&gt;// 4 bits — up to 16 weapons&lt;/span&gt;
    &lt;span class="n"&gt;TeamID&lt;/span&gt;    &lt;span class="kt"&gt;uint8&lt;/span&gt;  &lt;span class="s"&gt;`bits:"2"`&lt;/span&gt;  &lt;span class="c"&gt;// 2 bits — up to 4 teams&lt;/span&gt;
    &lt;span class="n"&gt;Health&lt;/span&gt;    &lt;span class="kt"&gt;uint16&lt;/span&gt; &lt;span class="s"&gt;`bits:"9"`&lt;/span&gt;  &lt;span class="c"&gt;// 9 bits — 0 to 511&lt;/span&gt;
    &lt;span class="n"&gt;PosX&lt;/span&gt;      &lt;span class="kt"&gt;int16&lt;/span&gt;  &lt;span class="s"&gt;`bits:"12"`&lt;/span&gt; &lt;span class="c"&gt;// 12 bits — signed position&lt;/span&gt;
    &lt;span class="n"&gt;PosY&lt;/span&gt;      &lt;span class="kt"&gt;int16&lt;/span&gt;  &lt;span class="s"&gt;`bits:"12"`&lt;/span&gt; &lt;span class="c"&gt;// 12 bits — signed position&lt;/span&gt;
    &lt;span class="n"&gt;Rotation&lt;/span&gt;  &lt;span class="kt"&gt;uint8&lt;/span&gt;  &lt;span class="s"&gt;`bits:"8"`&lt;/span&gt;  &lt;span class="c"&gt;// 8 bits — 0 to 255&lt;/span&gt;
    &lt;span class="n"&gt;Score&lt;/span&gt;     &lt;span class="kt"&gt;uint32&lt;/span&gt; &lt;span class="s"&gt;`bits:"16"`&lt;/span&gt; &lt;span class="c"&gt;// 16 bits — 0 to 65535&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// Total: 64 bits = 8 bytes exactly&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One struct. Eight fields. Eight bytes on the wire.&lt;br&gt;
That definition gives you five functions automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Marshal&lt;/strong&gt; — pack your struct into raw bytes ready &lt;br&gt;
to send over the wire:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;nibble&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Unmarshal&lt;/strong&gt; — parse incoming bytes back into your struct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;nibble&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Validate&lt;/strong&gt; — nibble knows the maximum value for every &lt;br&gt;
field from its bit width. A 9-bit field cannot exceed 511. &lt;br&gt;
nibble enforces this for every field automatically with &lt;br&gt;
no extra code from you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;nibble&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// returns ErrFieldOverflow if any field exceeds its bit width&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explain&lt;/strong&gt; — this is the one I personally find most useful. &lt;br&gt;
Paste in raw hex bytes and nibble tells you exactly what &lt;br&gt;
every single bit means in plain English:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;nibble&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Explain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GamePacket&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Byte 0 [10110011]:
  bit  0     → IsAlive:  true  (1)
  bits 1-4   → WeaponID: 9     (1001)
  bits 5-6   → TeamID:   1     (01)
  bit  7     → Health:   [continues...]
Byte 1 [00011111]:
  bits 0-8   → Health:   225
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I cannot tell you how many hours this would have saved me &lt;br&gt;
staring at hex dumps trying to work out which bits &lt;br&gt;
belong to which field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Diff&lt;/strong&gt; — compare two packets field by field. &lt;br&gt;
Invaluable when you are trying to understand what &lt;br&gt;
changed between two captures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;diffs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;nibble&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;packetA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;packetB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// Field     Before   After&lt;/span&gt;
&lt;span class="c"&gt;// Health    100      75&lt;/span&gt;
&lt;span class="c"&gt;// PosX      -86      -90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When your protocol changes — say health expands from &lt;br&gt;
8 bits to 9 bits — you update one struct tag. &lt;br&gt;
nibble recalculates everything. The bit math, &lt;br&gt;
the validation range, the marshal and unmarshal logic &lt;br&gt;
— all updated automatically. No hunting through &lt;br&gt;
manual bit shift code hoping you caught every place &lt;br&gt;
that needs updating.&lt;/p&gt;

&lt;p&gt;Truncated packet arriving from the network? &lt;br&gt;
nibble returns &lt;code&gt;ErrInsufficientData&lt;/code&gt; — not a panic. &lt;br&gt;
Your server stays up.&lt;/p&gt;

&lt;p&gt;Field overflow from a malicious client? &lt;br&gt;
Caught at the library level before it ever &lt;br&gt;
reaches your application logic.&lt;/p&gt;
&lt;h2&gt;
  
  
  The benchmarks
&lt;/h2&gt;

&lt;p&gt;I will be honest — the first version was not fast. &lt;br&gt;
2,100 nanoseconds per packet. Around 300 times slower &lt;br&gt;
than manual bit manipulation. That was reflection &lt;br&gt;
running on every single call with no caching. &lt;br&gt;
Not acceptable.&lt;/p&gt;

&lt;p&gt;The fix was schema caching. Parse the struct tags once, &lt;br&gt;
cache the full field layout in memory, reuse it on &lt;br&gt;
every subsequent call.&lt;/p&gt;

&lt;p&gt;Result: 182 nanoseconds per packet. An 11x improvement &lt;br&gt;
from one optimisation.&lt;/p&gt;

&lt;p&gt;Against go-bitfield — the closest existing library — &lt;br&gt;
nibble is consistently 10 times faster across every &lt;br&gt;
dataset size. 1,825 nanoseconds versus 182. &lt;br&gt;
And unlike go-bitfield, nibble actually has &lt;br&gt;
a Marshal path. They never implemented it.&lt;/p&gt;

&lt;p&gt;Against manual bit manipulation — yes, manual wins &lt;br&gt;
on raw speed. 6 nanoseconds versus 182. &lt;br&gt;
I am not hiding that number. Manual bit math &lt;br&gt;
at the CPU level will always be faster than &lt;br&gt;
reflection based code.&lt;/p&gt;

&lt;p&gt;But here is what that gap means in practice. &lt;br&gt;
At 100,000 packets per second — a realistic &lt;br&gt;
production game server load — nibble consumes &lt;br&gt;
less than 2% of one CPU core. The other 98% &lt;br&gt;
is free for your actual application logic.&lt;/p&gt;

&lt;p&gt;One thing worth being upfront about: nibble currently &lt;br&gt;
has 2 heap allocations per operation. Manual has zero. &lt;br&gt;
Eliminating those allocations is the next target &lt;br&gt;
for v0.2.0.&lt;/p&gt;

&lt;p&gt;The full interactive benchmark report is here if &lt;br&gt;
you want to dig into the numbers:&lt;br&gt;
&lt;a href="https://pavankumarms.github.io/nibble-benchmark/" rel="noopener noreferrer"&gt;https://pavankumarms.github.io/nibble-benchmark/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if you want to reproduce them yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/PavanKumarMS/nibble-benchmarks
&lt;span class="nb"&gt;cd &lt;/span&gt;nibble-benchmarks
go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-bench&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-benchmem&lt;/span&gt; &lt;span class="nt"&gt;-benchtime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10s ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;p&gt;If you work with any of these in Go — this is for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Game server backends&lt;/strong&gt; — real-time UDP state packets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IoT device hubs&lt;/strong&gt; — sensor payloads, CAN bus frames, 
BLE characteristics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VPN tooling&lt;/strong&gt; — WireGuard, Tailscale, Nebula 
all written in Go, all parsing binary headers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network security&lt;/strong&gt; — packet analysis, 
protocol fuzzing, CTF tooling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automotive&lt;/strong&gt; — CAN bus and EV telemetry backends&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And honestly — if you have ever written something like &lt;br&gt;
this in Go and stared at it wondering what it does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;weaponID&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="m"&gt;0xF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/PavanKumarMS/nibble@v0.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What is next
&lt;/h2&gt;

&lt;p&gt;There is plenty of room to improve and I have &lt;br&gt;
a clear list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eliminate the 2 heap allocations per operation&lt;/li&gt;
&lt;li&gt;Pre-built schemas for common protocols 
(TCP, UDP, DNS, BLE, CAN bus)&lt;/li&gt;
&lt;li&gt;Streaming encoder and decoder&lt;/li&gt;
&lt;li&gt;Schema DSL for cross-language code generation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  One more thing
&lt;/h2&gt;

&lt;p&gt;This is also my first time making a video &lt;br&gt;
instead of writing a post. Turns out talking &lt;br&gt;
to a camera is harder than debugging bit fields. &lt;br&gt;
If you prefer watching over reading the 12 minute &lt;br&gt;
walkthrough covers the whole story — the problem, &lt;br&gt;
the existing solutions, how nibble works, &lt;br&gt;
and what the benchmarks actually mean.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/0rXqRW8NXxc" rel="noopener noreferrer"&gt;Watch on YouTube →&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Links&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Library: &lt;a href="https://github.com/PavanKumarMS/nibble" rel="noopener noreferrer"&gt;https://github.com/PavanKumarMS/nibble&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Benchmarks: &lt;a href="https://pavankumarms.github.io/nibble-benchmark/" rel="noopener noreferrer"&gt;https://pavankumarms.github.io/nibble-benchmark/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go proposal that was closed: &lt;a href="https://github.com/golang/go/issues/29650" rel="noopener noreferrer"&gt;https://github.com/golang/go/issues/29650&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Python construct library: &lt;a href="https://construct.readthedocs.io" rel="noopener noreferrer"&gt;https://construct.readthedocs.io&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are working with binary protocols in Go &lt;br&gt;
I would genuinely love to hear your use case. &lt;br&gt;
What are you parsing? Is there something nibble &lt;br&gt;
is missing that would make it useful for you?&lt;/p&gt;

&lt;p&gt;Open an issue, drop a comment, or just star the &lt;br&gt;
repo if you think this fills a gap you have seen too.&lt;/p&gt;

</description>
      <category>go</category>
      <category>networking</category>
      <category>opensource</category>
      <category>gamedev</category>
    </item>
  </channel>
</rss>
