Skip to main content

CHANGELOG.md

# Changelog

## v2.8.0 (2026-06-24)

### Add
- Add `sampler` option to `use(Puid, ...)` with `:bit_shift` (default) and `:interval`
- Add interval/range entropy recycling sampler for non-power-of-2 charsets in `Puid.Bits`
- Add sampler-aware metrics API via `Puid.Chars.metrics/2`
- Add sampler-specific ETE reporting in `Puid` module info

### Changes
- Keep existing default generation behavior (`:bit_shift`) for backward compatibility
- Update README and benchmark scripts for sampler strategy comparison and ETE analysis
- Expand test coverage for sampler validation, efficiency, timing, and histogram behavior

## v2.7.1 (2026-01-13)

### Fix
- Fix bit shift pattern matching in `Puid.Bits` by using pin operator for bit size

## v2.7.0 (2025-10-18)

### Added
- Support for Elixir 1.19
- Added `:word_safe32` as new preferred atom for word-safe character set

### Changed
- Fixed preferred_cli_env deprecation warning by moving to cli/0 function

### Deprecated
- `:wordSafe32` atom is deprecated in favor of `:word_safe32`

## v2.6.0 (2025-09-05)

### Add

- `Puid.Chars.metrics/1` expose as public API
- add more predefined character sets
  - `:base36`: Used by many URL shorteners
  - `:base45`: Used in QR codes and text-based transport
  - `:base62`: Alias for :alphanum
  - `:base85`: Used in Adobe PostScript and PDF  
  - `:bech32`: Bitcoin SegWit address encoding
  - `:boolean`: binary/boolean representations
  - `:dna`: DNA nucleotide sequences
  - `:geohash`: Used in geographic coordinate encoding (base32 variant)
  - `:url_safe`: RFC 3986 unreserved characters
  - `:z_base32`: Zooko's human-oriented base32

### Changes

- Refactored internal ERE/ETE calculations to use centralized `Puid.Chars.metrics/1` function
- Increased predefined charsets from 20 to 31 (11 new charsets added)
- Added `:word_safe32` as the preferred name for `:wordSafe32` (backwards compatible)
## v2.5.0 (2025-09-01)

### Add

- `Puid.Chars.ete/1` function for calculating ETE of charsets
- `Puid.Chars.predefined/0` function to dynamically list predefined charset atoms
- `ete` field to `Puid.Info` structure showing Entropy Transform Efficiency
- `:base58` predefined charset using Bitcoin base58 alphabet (excludes 0, O, I, l)
- Comprehensive ETE benchmarks comparing Puid with other ID generation libraries
- ETE analysis scripts showing theoretical vs empirical efficiency
- Updated README for ETE and ERE

### Changes

- Minimum Elixir version bumped to 1.15 (from 1.14)

## v2.4.0 (2025-08-29)

### Changes

- Unify entropy approximations for `bits/2`, `total/2` and `risk/2` (removed small-total branch)
- Simplify README Comparisons; add Benchee usage instructions

### Add

- Benchee benchmark: `bench/compare.exs` (Puid-only and full comparison modes)
- GitHub Actions CI workflow: matrix build/test and dialyzer

### Fix

- Typespec consistency: non-bang functions now return `{:error, String.t()}`; bang variants raise `Puid.Error`
- Fix test bug in decode/encode roundtrip (use EDAscii correctly)
- `info/0` spec now returns `Puid.Info.t()`; added `Puid.Info.t` type

### Tooling

- mix: rename to `Puid.MixProject`; add `start_permanent`, docs extras, dialyzer flags, preferred_cli_env, package files
- Add Credo and `.credo.exs`
- Update deps: `ex_doc ~> 0.38`, `dialyxir 1.4.6`
- Remove `test/timing.exs`; use Benchee for performance comparisons

## v2.3.2 (2024-12-24)

### Fix Elixir 1.18 Range warning by explicitly declaring downward stepping on bit_shifts range

## v2.3.1 (2024-11-22)

### Minor mods for deprecations raised by Elixir 1.17

## v2.3.0 (2023-10-30)

### Add functions to `Puid` generated  modules

- `total/1` and `risk/1`
- `encode/1` and `decode/1`

## v2.2.0 (2023-08-23)

### Add predefined chars

- :base16
- :crockford32
- :word_safe32 (also accessible as :wordSafe32 for backwards compatibility)

### Minor

- Move `FixedBytes` from `Puid.Test` to `Puid.Util`
- Add bits per character to doc for predefined chars
- Use sigil_c for charlists
- Add a few more tests

## v2.1.0 (2023-01-29)

### Improve bit slicing optimization

- Bit slice shifts for a few character counts were missing a single bit optimization
- Update effected fixed byte tests and add histogram tests for correctness validation
- This change is an optimization and does not effect previous correctness

Note: This change warrants a minor version bump as any fixed byte testing using effected character counts must be updated. Any non-fixed-byte entropy source usage is unaffected.

### Address issue #13

- Add specified comparison notes
- Revamp README comparisons

## v2.0.6 (2023-01-06)

### Improve code point validation

- Reject utf8 code points between tilde and inverse bang
- General code cleanup regarding code point validation

## v2.0.5 (2022-12-19)

### Further prevention of issue #12

- Further prevention of macro generated `encode` function dialyzer warnings.
  - All combinations of pairs/single/unchunked encoding chunk sizes are now covered.
- This change does not effect functionality.

## v2.0.4 (2022-12-10)

### Fix issue #12

- Prevent macro generated `encode` function from encoding bit chunks known to be `<<>>`. Prior code resulted in dialyzer warnings.
- This change does not effect functionality.

## v2.0.3 (2022-08-21)

### Fix

- Fix FixBytes test helper. Only effects deterministic "random" bytes testing.
- This change does not effect functionality.

### Add

- Add cross-repo data for testing. This allows for easier, systematic histogram testing.
- Check for invalid ascii in `Puid.Chars.charlist/1` and `Puid.Chars.charlist!/1` calls

## v2.0.2 (2022-07-07)

### Fix

- Issue #10: Error 1st argument not a bitstring raised when just defining

### Testing

- Added tests for above fix
- Reworked fixed bytes mock entropy source
- Added **MODULE**.Bits.reset/1 to facilitate fixed bytes testing

## v2.0.1 (2022-07-01)

### Tests

- Added test for 100% coverage.

## v2.0.0 (2022-06-30)

### Added

- ASCII encoding optimization
  - Use cross-product character pairs to encode larger bit chunks
  - Encode remaining bits via single character strategy
- Unicode and/or ASCII-Unicode mix encoding optimization
  - Encode bits via single character strategy
- Optimize bit filtering in selection of random indexes
  - Minimize bit shifting for out-of-range index slices
- Store unused source entropy bits between `puid` generation calls per `Puid` module
- Speed and efficiency are independent of pre-defined vs custom characters, including Unicode
- Simplify module creation API
  - `chars` option can be a pre-defined atom, a string or a charlist
- Pre-defined :symbol characters
- Add chi square tests of random ID character histograms
- CHANGELOG

### Changes

- Remove `CryptoRand` dependency
  - Functionality superseded by new, in-project optimizations
- Update timing tests
- README

### Breaking Changes

- Removed `charset` option for pre-defined characters
  - Use the `chars` option instead
- Removed pre-defined `printable_ascii`
  - Replaced by `safe_ascii` (no backslash, backtick, single-quote or double-quote)
- Reverse argument order for `Puid.Entropy` utility functions
  - Allows idiomatic Elixir use. Note these functions are rarely used directly.

### Deprecated

- Removed deprecated functions
  - `Puid.Entropy.bits_for_length/2`
  - `Puid.Entropy.bits_for_length!/2`

## v1.1.2 (2021-09-15)

### Added

- Resolve Elixir 1.11 compilation warnings

### Changes

- Project file structure

### Fixes

- Correct `Error.reason()` in function specs

## v1.1.1 (2020-01-15)

### Deprecated

- `Puid.Entropy.bits_for_length/2`
- `Puid.Entropy.bits_for_length!/2`

## v1.1.0 (2020-01-14)

### Added

- Refactor
  - `Puid.Entropy.bits_for_length/2` -> `Puid.Entropy.bits_for_len/2`
  - `Puid.Entropy.bits_for_length!/2` -> `Puid.Entropy.bits_for_len!/2`

### Changes

- Timing tests
- README

## v1.0.0 (2019-05-02)

Initial release