Skip to content

Releases: RezaKargar/go-igbinary

v0.3.3

Choose a tag to compare

@RezaKargar RezaKargar released this 26 Jul 22:24

Documentation and repository-metadata release. No code or API changes — the decoder behaves exactly as in v0.3.2, so upgrading is optional.

This release makes the project easier for AI coding agents (and new contributors) to find, orient in, and change safely.

Agent onboarding

  • .cursor/rules/ is now tracked in git instead of being excluded by .gitignore, so the shared git-commit conventions actually ship with the repository. AGENTS.md already documented these rules as present — now they really are.
  • Added .github/copilot-instructions.md as a GitHub Copilot entrypoint that points at AGENTS.md.
  • AGENTS.md is now explicitly the single source of truth, with CLAUDE.md, the Copilot instructions, and the Cursor rules as thin pointers back to it.

AGENTS.md accuracy

  • Repository map expanded: memcached/ is broken out per file, including fastlz2.go (the self-contained FastLZ level-2 decompressor added in v0.3.2), and integration/ contents are described.
  • Corrected the root-package standard-library import list (strconv was missing) and documented the single permitted library dependency in memcached/.
  • Documented what CI actually runs, added the release process, and added a FastLZ troubleshooting entry to the task-routing section.

Discoverability

  • Repository topics and a pkg.go.dev homepage link were added so the module surfaces in GitHub and package-index searches.

Full changelog: v0.3.2...v0.3.3

v0.3.2

Choose a tag to compare

@RezaKargar RezaKargar released this 17 Jun 10:12

fastlz level 2 support

PHP's fastlz_compress switches from level 1 to level 2 for inputs ≥ 64 KB, and fastlz_decompress selects the decoder from the stream's first byte. The underlying dgryski/go-fastlz decoder implements level 1 only, so large memcached payloads (e.g. > 64 KB) failed with fastlz: corrupt input.

This release adds a pure-Go port of the reference fastlz2_decompress and dispatches to it based on the level encoded in the stream; level 1 continues to use go-fastlz.

  • No new dependencies (stdlib only)
  • Verified against the reference C implementation; the level-2 golden vector in testdata round-trips
  • Test suite stays cgo-free

v0.3.1

Choose a tag to compare

@RezaKargar RezaKargar released this 19 Feb 17:24

Full Changelog: v0.3.0...v0.3.1

v0.3.0

Choose a tag to compare

@RezaKargar RezaKargar released this 16 Feb 16:53

What's New

NormalizeArrays — Convert PHP sequential maps to Go slices

PHP does not distinguish indexed arrays from associative arrays at the igbinary level — both are encoded as key-value maps. A PHP indexed array like ["a","b","c"] decodes as map[string]any{"0":"a","1":"b","2":"c"}.

NormalizeArrays recursively converts such maps back into []any slices so that JSON serialization produces JSON arrays instead of JSON objects.

Usage

// Option A: manual post-processing
val, _ := igbinary.Decode(data)
val = igbinary.NormalizeArrays(val)

// Option B: automatic via decoder option
dec := igbinary.NewDecoder(igbinary.WithNormalizeArrays())
val, _ := dec.Decode(data)  // sequential maps are already []any

Rules

  • Empty maps → []any{}
  • Maps with keys "0","1",…,"N-1" → []any of length N (recursive)
  • All other maps → left as-is, values recursively normalized
  • Non-map/non-slice values → unchanged

Full Changelog: v0.2.1...v0.3.0

v0.2.1

Choose a tag to compare

@RezaKargar RezaKargar released this 15 Feb 20:24

Bug Fix

  • fix: do not register TypeStringEmpty in string dedup table — PHP igbinary treats TypeStringEmpty (0x0D) as a special marker that does not occupy a slot in the string deduplication table. The previous implementation incorrectly registered empty strings in both decodeValue() and decodeArrayKey(), causing all subsequent StringID lookups to be off by one whenever an empty string appeared in the data. This manifested as corrupted keys in structures like badge payloads where empty string values are common and later entries reference previously registered strings by ID.

Tests

  • Added 4 test cases covering the empty string dedup table behavior:
    • TestEmptyStringValueDoesNotShiftStringIDs — empty value followed by StringID reference
    • TestEmptyStringKeyDoesNotShiftStringIDs — empty key followed by StringID reference
    • TestMultipleEmptyStringsDoNotShiftStringIDs — multiple empty strings (key + value)
    • TestEmptyStringInNestedStructDoesNotShiftStringIDs — real-world badge-like nested structure

CI

  • Fixed Go version in test matrix (1.25 → 1.26) to match go.mod requirement
  • Fixed gofmt alignment in test cases

v0.2.0

Choose a tag to compare

@RezaKargar RezaKargar released this 15 Feb 20:24

What's Changed

Bug Fix: Array/Object Reference Resolution

The igbinary decoder previously discarded TypeArrayRef and TypeObjectRef back-reference IDs, always returning nil. This caused PHP values that share the same underlying zval (via copy-on-write semantics) to decode as nil in Go.

Root cause: When PHP assigns the same array to multiple keys without modification, igbinary serializes the first occurrence as a full array and subsequent occurrences as back-references (TypeArrayRef). The Go decoder was reading but discarding these reference IDs.

Changes

  • Added a compound value reference table (values []any) to the decoder's reader struct
  • Arrays and objects are registered in the table before populating their contents (supports circular references)
  • decodeRef now resolves references by looking up the table index instead of returning nil
  • Added ErrValueRefOutOfRange sentinel error for invalid reference IDs
  • Updated and added comprehensive tests for reference resolution scenarios
  • Bumped Go version to 1.26.0

Impact

This fix affects any PHP data where the same array or object is assigned to multiple locations within a single igbinary-serialized blob. All such cases are now correctly resolved.

v0.1.0 - Initial Release

Choose a tag to compare

@RezaKargar RezaKargar released this 15 Feb 11:56

go-igbinary v0.1.0

Pure Go decoder for PHP's igbinary serialization format.

Features

  • Zero external dependencies for the core igbinary package (stdlib only)
  • Decodes all igbinary v2 types: strings, integers, floats, booleans, nil, arrays, objects
  • String deduplication support (igbinary's compact string table)
  • PHP object decoding with class name preservation (__class key)
  • Class inheritance support (parent properties are flattened)

memcached sub-package

  • Full PHP memcached interop via flag-based dispatch
  • Built-in compressors: FastLZ, Zlib
  • Built-in serializers: igbinary, JSON, String, Long, Double, Bool
  • Pluggable Compressor and Serializer interfaces for custom implementations
  • Builder pattern for codec configuration

Installation

go get github.com/RezaKargar/go-igbinary@v0.1.0

Test Coverage

  • 93%+ overall test coverage
  • 88 unit tests + 21 integration tests (PHP writes to memcached, Go reads and decodes)
  • Docker-based integration tests (test-only dependency, not required by the library)