Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rehydration after structural cloning #317

Open
florianbepunkt opened this issue Feb 2, 2022 · 0 comments
Open

Rehydration after structural cloning #317

florianbepunkt opened this issue Feb 2, 2022 · 0 comments

Comments

@florianbepunkt
Copy link

florianbepunkt commented Feb 2, 2022

Structural Cloning a BigNumber instance removes all prototype methods and leaves a plain object, e. g.

const plainObj = { s: 1, e: -2, c: [ 50 ] }

I thought that it would be possible to rehydrate/restore a BigNumber obj like const bn = new BigNumber(plainObj), however the resulting value is alway NaN.

TDLR

import assert from 'assert';
import BigNumber from 'bignumber.js';

const obj = { c: [50], e: 1, s: 1 };
const rehydrated = new BigNumber(obj);

assert.strictEqual(BigNumber.isBigNumber(rehydrated), true);
assert.strictEqual(rehydrated.isNaN(), false);

Why is this? I thought the object would contain all "state" that is needed to recreate a BigNumber. Is there a way to achieve what I would like to do without converting the value to a string / number first?

EDIT
The cause of this issue is that
(a) BigNumber.js accepts an object literal, but you need to provide the property _isBigNumber: true to this literal
(b) Structured cloning removes _isBigNumber: true from the object

import BigNumber from 'bignumber.js';
import { deserialize, serialize } from 'v8';

const obj = { c: [50], e: 1, s: 1, _isBigNumber: true };
const rehydrated = new BigNumber(obj); // working
const clone = deserialize(serialize(rehydrated)); // structure cloning node.js
const rehydratedClone = new BigNumber(clone); // not working, since clone is missing _isBigNumber: true

Could we skip the _isBigNumber: true check in the constructor? If someone provides an object that adheres to BigNumber's data structure, couldn't we safely assume that this is a BigNumber? This would add the benefit, that BigNumber objects would be serializable via StructuredClone as well as JSON.

Possible solution

if (v && v._isBigNumber === true) {

Changing this to if (v && typeof v.c !== "undefined" && typeof v.s !== "undefined" && typeof v.e !== "undefined") { would solve the issue, while all tests still pass. So, basically an obj { s: 1, e: -2, c: [ 50 ] } is not a BigNumber, hence BigNumber.isBigNumber(obj) is false, but you can construct a BigNumber from it: new BigNumber(obj).

Then it only becomes a habit of coding to re-encode your BigNumber values before you use them, e. g.

const someFn = (valueThatMightBeSerializedOrNot: BigNumber) => new BigNumber(valueThatMightBeSerializedOrNot).plus(1);
@florianbepunkt florianbepunkt changed the title Add fn to rehydrate prototypes methods after structural cloning Rehydration after structural cloning Feb 2, 2022
florianbepunkt added a commit to florianbepunkt/bignumber.js that referenced this issue Feb 2, 2022
Fixes Rehydration after structural cloning MikeMcl#317.
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

No branches or pull requests

1 participant