Skip to content

Commit

Permalink
add BigInt.fromString and BigInt.fromNumber (#2399)
Browse files Browse the repository at this point in the history
  • Loading branch information
coleea authored Mar 25, 2024
1 parent 8c9abe2 commit 54b7c00
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/sixty-news-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": patch
---

add BigInt.fromString and BigInt.fromNumber
79 changes: 77 additions & 2 deletions packages/effect/src/BigInt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -547,14 +547,89 @@ export const multiplyAll = (collection: Iterable<bigint>): bigint => {
}

/**
* Convers a bigint into a number
* Takes a `bigint` and returns an `Option` of `number`.
*
* If the `bigint` is outside the safe integer range for JavaScript (`Number.MAX_SAFE_INTEGER`
* and `Number.MIN_SAFE_INTEGER`), it returns `Option.none()`. Otherwise, it converts the `bigint`
* to a number and returns `Option.some(number)`.
*
* @param b - The `bigint` to be converted to a `number`.
*
* @example
* import { toNumber } from "effect/BigInt"
* import { Option } from "effect"
*
* assert.deepStrictEqual(toNumber(BigInt(42)), Option.some(42))
* assert.deepStrictEqual(toNumber(BigInt(Number.MAX_SAFE_INTEGER) + BigInt(1)), Option.none())
* assert.deepStrictEqual(toNumber(BigInt(Number.MIN_SAFE_INTEGER) - BigInt(1)), Option.none())
*
* @since 2.0.0
* @category conversions
* @since 2.0.0
*/
export const toNumber = (b: bigint): Option.Option<number> => {
if (b > BigInt(Number.MAX_SAFE_INTEGER) || b < BigInt(Number.MIN_SAFE_INTEGER)) {
return Option.none()
}
return Option.some(Number(b))
}

/**
* Takes a string and returns an `Option` of `bigint`.
*
* If the string is empty or contains characters that cannot be converted into a `bigint`,
* it returns `Option.none()`, otherwise, it returns `Option.some(bigint)`.
*
* @param s - The string to be converted to a `bigint`.
*
* @example
* import { fromString } from "effect/BigInt"
* import { Option } from "effect"
*
* assert.deepStrictEqual(fromString("42"), Option.some(BigInt(42)))
* assert.deepStrictEqual(fromString(" "), Option.none())
* assert.deepStrictEqual(fromString("a"), Option.none())
*
* @category conversions
* @since 2.4.12
*/
export const fromString = (s: string): Option.Option<bigint> => {
try {
return s.trim() === ""
? Option.none()
: Option.some(BigInt(s))
} catch (_) {
return Option.none()
}
}

/**
* Takes a number and returns an `Option` of `bigint`.
*
* If the number is outside the safe integer range for JavaScript (`Number.MAX_SAFE_INTEGER`
* and `Number.MIN_SAFE_INTEGER`), it returns `Option.none()`. Otherwise, it attempts to
* convert the number to a `bigint` and returns `Option.some(bigint)`.
*
* @param n - The number to be converted to a `bigint`.
*
* @example
* import { fromNumber } from "effect/BigInt"
* import { Option } from "effect"
*
* assert.deepStrictEqual(fromNumber(42), Option.some(BigInt(42)))
* assert.deepStrictEqual(fromNumber(Number.MAX_SAFE_INTEGER + 1), Option.none())
* assert.deepStrictEqual(fromNumber(Number.MIN_SAFE_INTEGER - 1), Option.none())
*
* @category conversions
* @since 2.4.12
*/
export const fromNumber = (n: number): Option.Option<bigint> => {
if (n > Number.MAX_SAFE_INTEGER || n < Number.MIN_SAFE_INTEGER) {
return Option.none()
}

try {
return Option.some(BigInt(n))
} catch (_) {
return Option.none()
}
}
2 changes: 1 addition & 1 deletion packages/effect/src/Number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ export const sumAll = (collection: Iterable<number>): number => {
* @param collection - The collection of `number`s to multiply.
*
* @example
* import { multiplyAll } from 'effect/Number'
* import { multiplyAll } from "effect/Number"
*
* assert.deepStrictEqual(multiplyAll([2, 3, 4]), 24)
*
Expand Down
40 changes: 38 additions & 2 deletions packages/effect/test/BigInt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,43 @@ describe("BigInt", () => {
})

it("toNumber", () => {
assert.deepStrictEqual(BigInt_.toNumber(1n), Option.some(1))
assert.deepStrictEqual(BigInt_.toNumber(BigInt(Number.MAX_SAFE_INTEGER) + 1n), Option.none())
assert.deepStrictEqual(BigInt_.toNumber(BigInt(Number.MAX_SAFE_INTEGER)), Option.some(Number.MAX_SAFE_INTEGER))
assert.deepStrictEqual(BigInt_.toNumber(BigInt(Number.MAX_SAFE_INTEGER) + BigInt(1)), Option.none())
assert.deepStrictEqual(BigInt_.toNumber(BigInt(Number.MIN_SAFE_INTEGER)), Option.some(Number.MIN_SAFE_INTEGER))
assert.deepStrictEqual(BigInt_.toNumber(BigInt(Number.MIN_SAFE_INTEGER) - BigInt(1)), Option.none())
assert.deepStrictEqual(BigInt_.toNumber(BigInt(0)), Option.some(0))
assert.deepStrictEqual(BigInt_.toNumber(BigInt(42)), Option.some(42))
assert.deepStrictEqual(BigInt_.toNumber(BigInt(-42)), Option.some(-42))
})

it("fromString", () => {
assert.deepStrictEqual(BigInt_.fromString("NaN"), Option.none())
assert.deepStrictEqual(BigInt_.fromString("Infinity"), Option.none())
assert.deepStrictEqual(BigInt_.fromString("-Infinity"), Option.none())
assert.deepStrictEqual(BigInt_.fromString("3.14"), Option.none())
assert.deepStrictEqual(BigInt_.fromString("-3.14"), Option.none())
assert.deepStrictEqual(BigInt_.fromString("1e3"), Option.none())
assert.deepStrictEqual(BigInt_.fromString("1e-3"), Option.none())
assert.deepStrictEqual(BigInt_.fromString(""), Option.none())
assert.deepStrictEqual(BigInt_.fromString("a"), Option.none())
assert.deepStrictEqual(BigInt_.fromString("42"), Option.some(BigInt(42)))
assert.deepStrictEqual(BigInt_.fromString("\n\r\t 42 \n\r\t"), Option.some(BigInt(42)))
})

it("fromNumber", () => {
assert.deepStrictEqual(BigInt_.fromNumber(Number.MAX_SAFE_INTEGER), Option.some(BigInt(Number.MAX_SAFE_INTEGER)))
assert.deepStrictEqual(BigInt_.fromNumber(Number.MAX_SAFE_INTEGER + 1), Option.none())
assert.deepStrictEqual(BigInt_.fromNumber(Number.MIN_SAFE_INTEGER), Option.some(BigInt(Number.MIN_SAFE_INTEGER)))
assert.deepStrictEqual(BigInt_.fromNumber(Number.MIN_SAFE_INTEGER - 1), Option.none())
assert.deepStrictEqual(BigInt_.fromNumber(Infinity), Option.none())
assert.deepStrictEqual(BigInt_.fromNumber(-Infinity), Option.none())
assert.deepStrictEqual(BigInt_.fromNumber(NaN), Option.none())
assert.deepStrictEqual(BigInt_.fromNumber(1e100), Option.none())
assert.deepStrictEqual(BigInt_.fromNumber(-1e100), Option.none())
assert.deepStrictEqual(BigInt_.fromNumber(3.14), Option.none())
assert.deepStrictEqual(BigInt_.fromNumber(-3.14), Option.none())
assert.deepStrictEqual(BigInt_.fromNumber(0), Option.some(BigInt(0)))
assert.deepStrictEqual(BigInt_.fromNumber(42), Option.some(BigInt(42)))
assert.deepStrictEqual(BigInt_.fromNumber(-42), Option.some(BigInt(-42)))
})
})

0 comments on commit 54b7c00

Please sign in to comment.