Skip to content

Encode Decimals with positive exponents instead of trapping - #81

Open
deadcaf3 wants to merge 1 commit into
apple:mainfrom
deadcaf3:fix-decimal-positive-exponent
Open

deadcaf3 wants to merge 1 commit into
apple:mainfrom
deadcaf3:fix-decimal-positive-exponent

Conversation

@deadcaf3

Copy link
Copy Markdown

Motivation:

Foundation keeps trailing zeros in the exponent, so Decimal(100) is stored as significand 1, exponent 2. The encoder passed that straight to PseudoDecimal(mantissa:exponent:), which only accepts exponents from -3 to 0, so encoding a plain 100 crashed:

Fatal error: Invalid value for structured header decimal: mantissa 1 exponent 2

Any other Decimal that doesn't fit (too many digits, more than three decimal places) crashed the same way instead of throwing.

Modifications:

  • Replace the three copies of the Decimal conversion in the encoder with one throwing initializer. It folds a positive exponent back into the significand, then validates the result.
  • Make PseudoDecimal.validate package so the encoder can reuse it. No public API change.
  • Add a test covering items, lists, the largest value that fits, and one that doesn't.

Result:

Decimal(100) encodes as 100.0, and values that don't fit throw invalidIntegerOrDecimal rather than taking the process down.

Tested locally on macOS with Swift 6.4.1, swift test passes.

Motivation:

Foundation stores trailing zeros in a Decimal as a positive exponent, so
even Decimal(100) has significand 1 and exponent 2. The encoder passed
that exponent straight to PseudoDecimal, which only accepts exponents
from -3 to 0, so encoding it hit a precondition failure. Any other
out-of-range Decimal trapped the same way rather than throwing.

Modifications:

Move the three copies of the Decimal to PseudoDecimal conversion into a
single throwing initializer. It folds a positive exponent into the
significand and validates the result, throwing invalidIntegerOrDecimal
when the value cannot be represented. Expose PseudoDecimal.validate at
package level so the encoder can use it. Add an encoder test covering
items, lists and out-of-range values.

Result:

Decimals with positive exponents encode correctly, and unrepresentable
Decimals throw instead of crashing.
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.

1 participant