Migrating from 0.2 to 0.3
Copy MarkdownVersion 0.3 keeps the existing public function arities and success tuples. It raises the minimum Elixir version and stops encode operations from accepting decode-only labels.
Required: Elixir 1.15 or newer
EncodingRs now requires Elixir 1.15 because Rustler 0.38 and
rustler_precompiled 0.9 require it. Applications on Elixir 1.12–1.14 must
upgrade Elixir before updating EncodingRs.
def deps do
[{:encoding_rs, "~> 0.3.0"}]
endPer-operation options
Scheduler and input limits can now be selected at each call site:
EncodingRs.decode(data, "shift_jis",
dirty_threshold: 128 * 1024,
max_input_size: 10 * 1024 * 1024
)| API | Options apply to |
|---|---|
encode/3, decode/3, decode_with_details/3 | The complete input |
encode_batch/2, decode_batch/2, decode_batch_with_details/2 | Each item's size limit and the batch's combined scheduler threshold |
Decoder.new/2 | Every manual chunk decoded with that decoder |
Decoder.decode_chunk/4 | That chunk |
Decoder.stream/3, Decoder.stream_with_errors/3 | Every chunk in that stream |
Supported options are:
:dirty_threshold— non-negative byte count; defaults to 65,536.:max_input_size— non-negative byte count or:infinity; defaults to 104,857,600.
Options are validated with Keyword.validate!/2. Unknown keys and invalid
values raise ArgumentError instead of being ignored.
Existing config :encoding_rs values remain valid compatibility fallbacks.
Explicit options take precedence. :dirty_threshold remains a compile-time
fallback and :max_input_size remains a runtime fallback. No deprecation
warning is emitted during encoding or decoding.
Batch scheduler behavior changed
In 0.2, batch operations always ran on a dirty CPU scheduler. In 0.3, valid
items are totaled and the batch follows :dirty_threshold, just like a
one-shot operation. Oversized items are rejected before this total is
calculated.
To retain the 0.2 always-dirty behavior:
EncodingRs.decode_batch(items, dirty_threshold: 0)
EncodingRs.encode_batch(items, dirty_threshold: 0)The batch still crosses the NIF boundary once and preserves input order.
Detailed decoding is additive
decode/2 and decode/3 still return {:ok, string}. Use the new detailed API
when replacement or BOM selection must be observable:
{:ok, string, actual_encoding, had_errors} =
EncodingRs.decode_with_details(data, "windows-1252")The batch equivalent is decode_batch_with_details/2. Return shapes do not
depend on an option such as return_errors: true; callers choose the function
whose contract they need.
One-shot decoding has always allowed a leading UTF-8 or UTF-16 BOM to select
the actual decoder. Version 0.3 documents that behavior and exposes
actual_encoding; it does not change the decode/2 success tuple.
Only the native sentinel for an unrecognized encoding is normalized to
:unknown_encoding. Unexpected native error reasons are now preserved instead
of being mislabeled. Callers should retain a general {:error, reason} branch.
Stateful decoder contracts
Decoder.new/1 still returns the same opaque reference. Existing
decode_chunk/2, decode_chunk/3, decode_chunk!/2, and decode_chunk!/3
calls remain valid. Decoder.new/2 and new!/2 return an opaque configured
decoder that stores validated options once. The other new option-taking forms
are decode_chunk/4, stream/3, and stream_with_errors/3.
Stream options are resolved once when enumeration starts, then reused for all
chunks. For manual loops, prefer new/2 plus decode_chunk/3.
Decoder.decode_chunk/4 may return {:error, :allocation_failed} if its output
buffer cannot be allocated. This is in addition to :input_too_large and
:lock_poisoned. Code that exhaustively matches decoder errors should add a
fallback or handle this atom.
Other API additions and clarifications
EncodingRs.available?/0checks whether the native implementation loaded without raising for:nif_not_loadedor:undef.- Existing application startup behavior is unchanged. The package no longer
sets project-only
start_permanentmetadata.
Decode-only labels now fail encoding
In 0.2, encoding to UTF-16LE, UTF-16BE, or replacement silently produced
UTF-8 because those WHATWG encodings have UTF-8 as their output encoding. In
0.3, one-shot and batch encode operations return
{:error, :encoder_unavailable} instead. Bang variants raise ArgumentError.
Use a dedicated UTF-16 encoder when UTF-16 output is required.
Upgrade checklist
- Upgrade to Elixir 1.15 or newer.
- Change the dependency requirement to
~> 0.3.0and refresh the lockfile. - If batches must always use dirty schedulers, pass
dirty_threshold: 0. - Audit encode calls that pass UTF-16 or
replacementlabels. - Audit exhaustive matches on stateful decoder errors.
- Use explicit operation options for reusable libraries; existing application configuration can remain while migrating call sites.