Skip to content

feat(intid): add encode_int_base10 / decode_int_base10[_bounded]#81

Merged
nao1215 merged 1 commit into
mainfrom
feat/issue-78-intid-base10-symmetry
May 9, 2026
Merged

feat(intid): add encode_int_base10 / decode_int_base10[_bounded]#81
nao1215 merged 1 commit into
mainfrom
feat/issue-78-intid-base10-symmetry

Conversation

@nao1215
Copy link
Copy Markdown
Owner

@nao1215 nao1215 commented May 9, 2026

Summary

yabase/intid exposed encode/decode/bounded-decode helpers for
every other base (base32 RFC 4648 / Crockford, base36, base58
Bitcoin / Flickr, base62) but skipped decimal. The omission broke
switch-case bench harnesses ("swap base58 for base62 to compare
ID lengths, hit a compile error on encode_int_base10") and
forced callers to special-case decimal with int.to_string /
int.parse plus a hand-rolled bounds check. Add the missing
trio.

Changes

src/yabase/intid.gleam

  • New imports: yabase/base10.
  • encode_int_base10(value: Int) -> String — routes through
    base10.encode(int_to_bytes_be(value)).
  • decode_int_base10(input: String) -> Result(Int, CodecError)
    routes through base10.decode(input) |> result.map(bytes_to_int)
    with the same reject_empty guard as base36 / base58 / base62.
  • decode_int_base10_bounded(input:, max:) -> Result(Int, CodecError)
    — wraps decode_int_base10 with the existing bound_check.
  • All three sit between the base32 Crockford block and the
    base36 block to keep the source ordering by base value.

test/intid_test.gleam

  • New === encoding.base10() (#78) === test block covering:
    • encode: zero, single-digit, two-digit carry, large value
      (1B).
    • decode: empty rejection, round-trip, leading-zero
      tolerance (\"0042\" == \"42\"), invalid character
      mid-string.
    • _bounded: under / at / over max boundary.

CHANGELOG.md

  • Added entry under [Unreleased].

Design Decisions

Why route through base10 rather than int.to_string. The
issue's recommended approach was option 1 ("add the helpers for
symmetry"). Routing through base10 keeps the implementation
byte-for-byte identical to the other encode_int_* functions,
so the contract — empty input rejection, leading-zero
tolerance, byte-roundtrip semantics — matches without
case-by-case behaviour. Using int.to_string / int.parse
directly would diverge on the leading-zero case
(int.parse(\"0042\") == Ok(42) doesn't preserve the
\"0042\" shape on round-trip the way the byte path does).

Why no _strict variant. Other intid functions don't have
a _strict form either — the _bounded family is the only
"reject more inputs" variant. Keeping the surface symmetric
with the rest of the family is the explicit goal of #78.

Test plan

  • gleam test — 791 passed (was 780; +11 new tests)
  • just check — format-check + lint + check + build + test
  • Switch-case bench harnesses (the issue's repro shape) now
    compile cleanly with intid.encode_int_base10(seq) /
    intid.encode_int_base58(seq) / intid.encode_int_base62(seq)
    lined up.

Closes #78.

`yabase/intid` exposed encode/decode/bounded-decode helpers for
every other base (base32 RFC 4648 / Crockford, base36, base58
Bitcoin / Flickr, base62) but skipped decimal. The omission
broke switch-case bench harnesses ("swap base58 for base62 to
compare ID lengths, hit a compile error on
`encode_int_base10`") and forced callers to special-case decimal
with `int.to_string` / `int.parse` plus a hand-rolled bounds
check.

Add the missing trio:

- `encode_int_base10(value: Int) -> String`
- `decode_int_base10(input: String) -> Result(Int, CodecError)`
- `decode_int_base10_bounded(input:, max:) -> Result(Int, CodecError)`

All three route through `yabase/base10` (the existing
BitArray-level decimal codec) plus the same `int_to_bytes_be` /
`bytes_to_int` helpers the other `_int_*` functions use, so the
contract is byte-for-byte identical to base36 / base58 /
base62: empty input → `Error(InvalidLength(0))`, leading-zero
input is tolerated (matches the `decode_int_base36("0042") ==
decode_int_base36("42")` shape), `_bounded` returns
`Error(Overflow)` when the decoded value exceeds `max`.

Tests cover: zero, single-digit, two-digit carry, large value
(1B), empty rejection, round-trip, leading-zero tolerance,
invalid character mid-string, bounded under / at / over `max`.

Closes #78.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 9, 2026

Warning

Rate limit exceeded

@nao1215 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 52 minutes and 55 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 037ed746-ced0-4f2d-9d3c-23efa3f11d25

📥 Commits

Reviewing files that changed from the base of the PR and between df4f2ab and a3cbc78.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/yabase/intid.gleam
  • test/intid_test.gleam
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-78-intid-base10-symmetry

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nao1215 nao1215 merged commit a3c9772 into main May 9, 2026
8 checks passed
@nao1215 nao1215 deleted the feat/issue-78-intid-base10-symmetry branch May 9, 2026 22:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

intid: missing encode_int_base10 / decode_int_base10 breaks API symmetry

1 participant