Skip to content

Commit b9cb3a9

Browse files
authoredFeb 21, 2024··
feat: added Number.parse and BigInt.toNumber (#2193)
1 parent 2ea4c83 commit b9cb3a9

File tree

8 files changed

+127
-92
lines changed

8 files changed

+127
-92
lines changed
 

‎.changeset/heavy-rings-rhyme.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"effect": patch
3+
"@effect/schema": patch
4+
---
5+
6+
added Number.parse, BigInt.toNumber, ParseResult.fromOption

‎packages/effect/src/BigInt.ts

+13
Original file line numberDiff line numberDiff line change
@@ -545,3 +545,16 @@ export const multiplyAll = (collection: Iterable<bigint>): bigint => {
545545
}
546546
return out
547547
}
548+
549+
/**
550+
* Convers a bigint into a number
551+
*
552+
* @since 2.0.0
553+
* @category conversions
554+
*/
555+
export const toNumber = (b: bigint): Option.Option<number> => {
556+
if (b > BigInt(Number.MAX_SAFE_INTEGER) || b < BigInt(Number.MIN_SAFE_INTEGER)) {
557+
return Option.none()
558+
}
559+
return Option.some(Number(b))
560+
}

‎packages/effect/src/Number.ts

+26
Original file line numberDiff line numberDiff line change
@@ -467,3 +467,29 @@ export const nextPow2 = (n: number): number => {
467467
const nextPow = Math.ceil(Math.log(n) / Math.log(2))
468468
return Math.max(Math.pow(2, nextPow), 2)
469469
}
470+
471+
/**
472+
* Tries to parse a `number` from a `string` using the `Number()` function.
473+
* The following special string values are supported: "NaN", "Infinity", "-Infinity".
474+
*
475+
* @category constructors
476+
* @since 2.0.0
477+
*/
478+
export const parse = (s: string): Option<number> => {
479+
if (s === "NaN") {
480+
return option.some(NaN)
481+
}
482+
if (s === "Infinity") {
483+
return option.some(Infinity)
484+
}
485+
if (s === "-Infinity") {
486+
return option.some(-Infinity)
487+
}
488+
if (s.trim() === "") {
489+
return option.none
490+
}
491+
const n = Number(s)
492+
return Number.isNaN(n)
493+
? option.none
494+
: option.some(n)
495+
}

‎packages/effect/test/BigInt.test.ts

+62-57
Original file line numberDiff line numberDiff line change
@@ -1,143 +1,148 @@
11
import { deepStrictEqual } from "effect-test/util"
2-
import * as BigInt from "effect/BigInt"
2+
import * as BigInt_ from "effect/BigInt"
33
import { pipe } from "effect/Function"
44
import * as Option from "effect/Option"
55
import { assert, describe, expect, it } from "vitest"
66

77
describe("BigInt", () => {
88
it("sign", () => {
9-
assert.deepStrictEqual(BigInt.sign(-5n), -1)
10-
assert.deepStrictEqual(BigInt.sign(0n), 0)
11-
assert.deepStrictEqual(BigInt.sign(5n), 1)
9+
assert.deepStrictEqual(BigInt_.sign(-5n), -1)
10+
assert.deepStrictEqual(BigInt_.sign(0n), 0)
11+
assert.deepStrictEqual(BigInt_.sign(5n), 1)
1212
})
1313

1414
it("isBigInt", () => {
15-
expect(BigInt.isBigInt(1n)).toEqual(true)
16-
expect(BigInt.isBigInt(1)).toEqual(false)
17-
expect(BigInt.isBigInt("a")).toEqual(false)
18-
expect(BigInt.isBigInt(true)).toEqual(false)
15+
expect(BigInt_.isBigInt(1n)).toEqual(true)
16+
expect(BigInt_.isBigInt(1)).toEqual(false)
17+
expect(BigInt_.isBigInt("a")).toEqual(false)
18+
expect(BigInt_.isBigInt(true)).toEqual(false)
1919
})
2020

2121
it("sum", () => {
22-
deepStrictEqual(pipe(1n, BigInt.sum(2n)), 3n)
22+
deepStrictEqual(pipe(1n, BigInt_.sum(2n)), 3n)
2323
})
2424

2525
it("multiply", () => {
26-
deepStrictEqual(pipe(2n, BigInt.multiply(3n)), 6n)
26+
deepStrictEqual(pipe(2n, BigInt_.multiply(3n)), 6n)
2727
})
2828

2929
it("subtract", () => {
30-
deepStrictEqual(pipe(3n, BigInt.subtract(1n)), 2n)
30+
deepStrictEqual(pipe(3n, BigInt_.subtract(1n)), 2n)
3131
})
3232

3333
it("divide", () => {
34-
deepStrictEqual(pipe(6n, BigInt.divide(2n)), Option.some(3n))
35-
deepStrictEqual(pipe(6n, BigInt.divide(0n)), Option.none())
34+
deepStrictEqual(pipe(6n, BigInt_.divide(2n)), Option.some(3n))
35+
deepStrictEqual(pipe(6n, BigInt_.divide(0n)), Option.none())
3636
})
3737

3838
it("unsafeDivide", () => {
39-
deepStrictEqual(pipe(6n, BigInt.unsafeDivide(2n)), 3n)
39+
deepStrictEqual(pipe(6n, BigInt_.unsafeDivide(2n)), 3n)
4040
})
4141

4242
it("increment", () => {
43-
deepStrictEqual(BigInt.increment(2n), 3n)
43+
deepStrictEqual(BigInt_.increment(2n), 3n)
4444
})
4545

4646
it("decrement", () => {
47-
deepStrictEqual(BigInt.decrement(2n), 1n)
47+
deepStrictEqual(BigInt_.decrement(2n), 1n)
4848
})
4949

5050
it("Equivalence", () => {
51-
expect(BigInt.Equivalence(1n, 1n)).toBe(true)
52-
expect(BigInt.Equivalence(1n, 2n)).toBe(false)
51+
expect(BigInt_.Equivalence(1n, 1n)).toBe(true)
52+
expect(BigInt_.Equivalence(1n, 2n)).toBe(false)
5353
})
5454

5555
it("Order", () => {
56-
deepStrictEqual(BigInt.Order(1n, 2n), -1)
57-
deepStrictEqual(BigInt.Order(2n, 1n), 1)
58-
deepStrictEqual(BigInt.Order(2n, 2n), 0)
56+
deepStrictEqual(BigInt_.Order(1n, 2n), -1)
57+
deepStrictEqual(BigInt_.Order(2n, 1n), 1)
58+
deepStrictEqual(BigInt_.Order(2n, 2n), 0)
5959
})
6060

6161
it("lessThan", () => {
62-
assert.deepStrictEqual(BigInt.lessThan(2n, 3n), true)
63-
assert.deepStrictEqual(BigInt.lessThan(3n, 3n), false)
64-
assert.deepStrictEqual(BigInt.lessThan(4n, 3n), false)
62+
assert.deepStrictEqual(BigInt_.lessThan(2n, 3n), true)
63+
assert.deepStrictEqual(BigInt_.lessThan(3n, 3n), false)
64+
assert.deepStrictEqual(BigInt_.lessThan(4n, 3n), false)
6565
})
6666

6767
it("lessThanOrEqualTo", () => {
68-
assert.deepStrictEqual(BigInt.lessThanOrEqualTo(2n, 3n), true)
69-
assert.deepStrictEqual(BigInt.lessThanOrEqualTo(3n, 3n), true)
70-
assert.deepStrictEqual(BigInt.lessThanOrEqualTo(4n, 3n), false)
68+
assert.deepStrictEqual(BigInt_.lessThanOrEqualTo(2n, 3n), true)
69+
assert.deepStrictEqual(BigInt_.lessThanOrEqualTo(3n, 3n), true)
70+
assert.deepStrictEqual(BigInt_.lessThanOrEqualTo(4n, 3n), false)
7171
})
7272

7373
it("greaterThan", () => {
74-
assert.deepStrictEqual(BigInt.greaterThan(2n, 3n), false)
75-
assert.deepStrictEqual(BigInt.greaterThan(3n, 3n), false)
76-
assert.deepStrictEqual(BigInt.greaterThan(4n, 3n), true)
74+
assert.deepStrictEqual(BigInt_.greaterThan(2n, 3n), false)
75+
assert.deepStrictEqual(BigInt_.greaterThan(3n, 3n), false)
76+
assert.deepStrictEqual(BigInt_.greaterThan(4n, 3n), true)
7777
})
7878

7979
it("greaterThanOrEqualTo", () => {
80-
assert.deepStrictEqual(BigInt.greaterThanOrEqualTo(2n, 3n), false)
81-
assert.deepStrictEqual(BigInt.greaterThanOrEqualTo(3n, 3n), true)
82-
assert.deepStrictEqual(BigInt.greaterThanOrEqualTo(4n, 3n), true)
80+
assert.deepStrictEqual(BigInt_.greaterThanOrEqualTo(2n, 3n), false)
81+
assert.deepStrictEqual(BigInt_.greaterThanOrEqualTo(3n, 3n), true)
82+
assert.deepStrictEqual(BigInt_.greaterThanOrEqualTo(4n, 3n), true)
8383
})
8484

8585
it("between", () => {
86-
assert.deepStrictEqual(BigInt.between({ minimum: 0n, maximum: 5n })(3n), true)
87-
assert.deepStrictEqual(BigInt.between({ minimum: 0n, maximum: 5n })(-1n), false)
88-
assert.deepStrictEqual(BigInt.between({ minimum: 0n, maximum: 5n })(6n), false)
86+
assert.deepStrictEqual(BigInt_.between({ minimum: 0n, maximum: 5n })(3n), true)
87+
assert.deepStrictEqual(BigInt_.between({ minimum: 0n, maximum: 5n })(-1n), false)
88+
assert.deepStrictEqual(BigInt_.between({ minimum: 0n, maximum: 5n })(6n), false)
8989

90-
assert.deepStrictEqual(BigInt.between(3n, { minimum: 0n, maximum: 5n }), true)
90+
assert.deepStrictEqual(BigInt_.between(3n, { minimum: 0n, maximum: 5n }), true)
9191
})
9292

9393
it("clamp", () => {
94-
assert.deepStrictEqual(BigInt.clamp({ minimum: 0n, maximum: 5n })(3n), 3n)
95-
assert.deepStrictEqual(BigInt.clamp({ minimum: 0n, maximum: 5n })(-1n), 0n)
96-
assert.deepStrictEqual(BigInt.clamp({ minimum: 0n, maximum: 5n })(6n), 5n)
94+
assert.deepStrictEqual(BigInt_.clamp({ minimum: 0n, maximum: 5n })(3n), 3n)
95+
assert.deepStrictEqual(BigInt_.clamp({ minimum: 0n, maximum: 5n })(-1n), 0n)
96+
assert.deepStrictEqual(BigInt_.clamp({ minimum: 0n, maximum: 5n })(6n), 5n)
9797

98-
assert.deepStrictEqual(BigInt.clamp(3n, { minimum: 0n, maximum: 5n }), 3n)
98+
assert.deepStrictEqual(BigInt_.clamp(3n, { minimum: 0n, maximum: 5n }), 3n)
9999
})
100100

101101
it("min", () => {
102-
assert.deepStrictEqual(BigInt.min(2n, 3n), 2n)
102+
assert.deepStrictEqual(BigInt_.min(2n, 3n), 2n)
103103
})
104104

105105
it("max", () => {
106-
assert.deepStrictEqual(BigInt.max(2n, 3n), 3n)
106+
assert.deepStrictEqual(BigInt_.max(2n, 3n), 3n)
107107
})
108108

109109
it("sumAll", () => {
110-
assert.deepStrictEqual(BigInt.sumAll([2n, 3n, 4n]), 9n)
110+
assert.deepStrictEqual(BigInt_.sumAll([2n, 3n, 4n]), 9n)
111111
})
112112

113113
it("multiplyAll", () => {
114-
assert.deepStrictEqual(BigInt.multiplyAll([2n, 0n, 4n]), 0n)
115-
assert.deepStrictEqual(BigInt.multiplyAll([2n, 3n, 4n]), 24n)
114+
assert.deepStrictEqual(BigInt_.multiplyAll([2n, 0n, 4n]), 0n)
115+
assert.deepStrictEqual(BigInt_.multiplyAll([2n, 3n, 4n]), 24n)
116116
})
117117

118118
it("abs", () => {
119-
assert.deepStrictEqual(BigInt.abs(2n), 2n)
120-
assert.deepStrictEqual(BigInt.abs(-3n), 3n)
119+
assert.deepStrictEqual(BigInt_.abs(2n), 2n)
120+
assert.deepStrictEqual(BigInt_.abs(-3n), 3n)
121121
})
122122

123123
it("gcd", () => {
124-
assert.deepStrictEqual(BigInt.gcd(2n, 4n), 2n)
125-
assert.deepStrictEqual(BigInt.gcd(3n, 4n), 1n)
124+
assert.deepStrictEqual(BigInt_.gcd(2n, 4n), 2n)
125+
assert.deepStrictEqual(BigInt_.gcd(3n, 4n), 1n)
126126
})
127127

128128
it("lcm", () => {
129-
assert.deepStrictEqual(BigInt.lcm(2n, 4n), 4n)
130-
assert.deepStrictEqual(BigInt.lcm(3n, 4n), 12n)
129+
assert.deepStrictEqual(BigInt_.lcm(2n, 4n), 4n)
130+
assert.deepStrictEqual(BigInt_.lcm(3n, 4n), 12n)
131131
})
132132

133133
it("sqrt", () => {
134-
assert.deepStrictEqual(BigInt.sqrt(1n), Option.some(1n))
135-
assert.deepStrictEqual(BigInt.sqrt(16n), Option.some(4n))
136-
assert.deepStrictEqual(BigInt.sqrt(81n), Option.some(9n))
137-
assert.deepStrictEqual(BigInt.sqrt(-123n), Option.none())
134+
assert.deepStrictEqual(BigInt_.sqrt(1n), Option.some(1n))
135+
assert.deepStrictEqual(BigInt_.sqrt(16n), Option.some(4n))
136+
assert.deepStrictEqual(BigInt_.sqrt(81n), Option.some(9n))
137+
assert.deepStrictEqual(BigInt_.sqrt(-123n), Option.none())
138138
})
139139

140140
it("sqrt", () => {
141-
expect(() => BigInt.unsafeSqrt(-1n)).toThrow(new Error("Cannot take the square root of a negative number"))
141+
expect(() => BigInt_.unsafeSqrt(-1n)).toThrow(new Error("Cannot take the square root of a negative number"))
142+
})
143+
144+
it("toNumber", () => {
145+
assert.deepStrictEqual(BigInt_.toNumber(1n), Option.some(1))
146+
assert.deepStrictEqual(BigInt_.toNumber(BigInt(Number.MAX_SAFE_INTEGER) + 1n), Option.none())
142147
})
143148
})

‎packages/effect/test/Number.test.ts

+8
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,12 @@ describe("Number", () => {
127127
assert.deepStrictEqual(Number.multiplyAll([2, 0, 4]), 0)
128128
assert.deepStrictEqual(Number.multiplyAll([2, 3, 4]), 24)
129129
})
130+
131+
it("parse", () => {
132+
assert.deepStrictEqual(Number.parse("NaN"), Option.some(NaN))
133+
assert.deepStrictEqual(Number.parse("Infinity"), Option.some(Infinity))
134+
assert.deepStrictEqual(Number.parse("-Infinity"), Option.some(-Infinity))
135+
assert.deepStrictEqual(Number.parse("42"), Option.some(42))
136+
assert.deepStrictEqual(Number.parse("a"), Option.none())
137+
})
130138
})

‎packages/schema/src/ParseResult.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import { TaggedError } from "effect/Data"
66
import * as Effect from "effect/Effect"
77
import * as Either from "effect/Either"
8-
import { dual } from "effect/Function"
98
import type { LazyArg } from "effect/Function"
9+
import { dual } from "effect/Function"
1010
import * as Inspectable from "effect/Inspectable"
1111
import type * as Option from "effect/Option"
1212
import type * as ReadonlyArray from "effect/ReadonlyArray"
@@ -75,6 +75,15 @@ export {
7575
_try as try
7676
}
7777

78+
/**
79+
* @category constructors
80+
* @since 1.0.0
81+
*/
82+
export const fromOption: {
83+
<A>(self: Option.Option<A>, onNone: () => ParseIssue): Either.Either<ParseIssue, A>
84+
<A>(onNone: () => ParseIssue): (self: Option.Option<A>) => Either.Either<ParseIssue, A>
85+
} = Either.fromOption
86+
7887
/**
7988
* `ParseIssue` is a type that represents the different types of errors that can occur when decoding/encoding a value.
8089
*

‎packages/schema/src/Schema.ts

+2-25
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import * as ArrayFormatter from "./ArrayFormatter.js"
3737
import type { ParseOptions } from "./AST.js"
3838
import * as AST from "./AST.js"
3939
import * as Internal from "./internal/ast.js"
40-
import * as InternalBigInt from "./internal/bigint.js"
4140
import * as filters from "./internal/filters.js"
4241
import * as hooks from "./internal/hooks.js"
4342
import * as InternalSchema from "./internal/schema.js"
@@ -2837,24 +2836,7 @@ export const clamp =
28372836
export const NumberFromString: Schema<number, string> = transformOrFail(
28382837
string,
28392838
number,
2840-
(s, _, ast) => {
2841-
if (s === "NaN") {
2842-
return ParseResult.succeed(NaN)
2843-
}
2844-
if (s === "Infinity") {
2845-
return ParseResult.succeed(Infinity)
2846-
}
2847-
if (s === "-Infinity") {
2848-
return ParseResult.succeed(-Infinity)
2849-
}
2850-
if (s.trim() === "") {
2851-
return ParseResult.fail(ParseResult.type(ast, s))
2852-
}
2853-
const n = Number(s)
2854-
return Number.isNaN(n)
2855-
? ParseResult.fail(ParseResult.type(ast, s))
2856-
: ParseResult.succeed(n)
2857-
},
2839+
(s, _, ast) => ParseResult.fromOption(N.parse(s), () => ParseResult.type(ast, s)),
28582840
(n) => ParseResult.succeed(String(n))
28592841
).pipe(identifier("NumberFromString"))
28602842

@@ -3267,12 +3249,7 @@ export const BigintFromNumber: Schema<bigint, number> = transformOrFail(
32673249
try: () => BigInt(n),
32683250
catch: () => ParseResult.type(ast, n)
32693251
}),
3270-
(b, _, ast) => {
3271-
if (b > InternalBigInt.maxSafeInteger || b < InternalBigInt.minSafeInteger) {
3272-
return ParseResult.fail(ParseResult.type(ast, b))
3273-
}
3274-
return ParseResult.succeed(Number(b))
3275-
}
3252+
(b, _, ast) => ParseResult.fromOption(BigInt_.toNumber(b), () => ParseResult.type(ast, b))
32763253
).pipe(identifier("BigintFromNumber"))
32773254

32783255
/**

‎packages/schema/src/internal/bigint.ts

-9
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.