-
Notifications
You must be signed in to change notification settings - Fork 37
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
Add managed decimal support (as in the rust framework) #477
Changes from 3 commits
615034c
c59657d
ad8d581
ab476cf
9dceb18
06b85fe
e35ad8f
6065dee
0d9e486
5a11659
42bf1c6
dada969
73670bd
1f65ffe
8e054c6
9135302
33a875d
14b2f5f
275bb49
0ca88e9
3838dc7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { assert } from "chai"; | ||
import { ManagedDecimalType, ManagedDecimalValue } from "./managedDecimal"; | ||
import BigNumber from "bignumber.js"; | ||
|
||
describe("test managed decimal", () => { | ||
it("should get correct metadata set", () => { | ||
let type = new ManagedDecimalType("8"); | ||
const expectedMetadata = "8"; | ||
|
||
assert.equal(type.getMetadata(), expectedMetadata); | ||
assert.isFalse(type.isVariable()); | ||
}); | ||
|
||
it("should get correct metadata set when variable", () => { | ||
let type = new ManagedDecimalType("usize"); | ||
const expectedMetadata = "usize"; | ||
|
||
assert.equal(type.getMetadata(), expectedMetadata); | ||
assert.isTrue(type.isVariable()); | ||
}); | ||
|
||
it("should return the expected values for scale and metadata", () => { | ||
let firstValue = new ManagedDecimalValue(new BigNumber(1), 2, false); | ||
let secondValue = new ManagedDecimalValue(new BigNumber(2), 2, false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here / above / below - can also be |
||
const expectedMetadata = "2"; | ||
const type = firstValue.getType() as ManagedDecimalType; | ||
|
||
assert.equal(type.getMetadata(), expectedMetadata); | ||
assert.isFalse(type.isVariable()); | ||
assert.equal(firstValue.getScale(), 2); | ||
assert.equal(firstValue.toString(), "1.00"); | ||
assert.isFalse(firstValue.equals(secondValue)); | ||
}); | ||
|
||
it("should compare correctly two managed decimals even with different scale", () => { | ||
let firstValue = new ManagedDecimalValue(new BigNumber(1.234), 3, false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For documentation purposes, when a
Instead of:
Since in the constructor of |
||
let secondValue = new ManagedDecimalValue(new BigNumber(12.34), 2, false); | ||
|
||
assert.isFalse(firstValue.equals(secondValue)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's have a "positive" equality test / equal values, as well. |
||
}); | ||
|
||
it("should set the correct scale when variable decimals", () => { | ||
let value = new ManagedDecimalValue(new BigNumber(1.3), 2, true); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry for not thinking of this before - how about:
Using the trick |
||
const expectedMetadata = "usize"; | ||
const type = value.getType() as ManagedDecimalType; | ||
|
||
assert.equal(type.getMetadata(), expectedMetadata); | ||
assert.isTrue(type.isVariable()); | ||
assert.equal(value.toString(), "1.30"); | ||
assert.equal(value.getScale(), 2); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,6 @@ import { Type, TypedValue } from "./types"; | |
|
||
export class ManagedDecimalType extends Type { | ||
static ClassName = "ManagedDecimalType"; | ||
private readonly scale: any; | ||
|
||
constructor(metadata: any) { | ||
super("ManagedDecimal", undefined, undefined, metadata); | ||
|
@@ -67,19 +66,21 @@ export class ManagedDecimalValue extends TypedValue { | |
|
||
export class ManagedDecimalSignedType extends Type { | ||
static ClassName = "ManagedDecimalSignedType"; | ||
private readonly scale: number; | ||
|
||
constructor(scale: number) { | ||
super("ManagedDecimalSigned", undefined, undefined, scale); | ||
this.scale = scale; | ||
constructor(metadata: any) { | ||
super("ManagedDecimalSigned", undefined, undefined, metadata); | ||
} | ||
|
||
getClassName(): string { | ||
return ManagedDecimalType.ClassName; | ||
} | ||
|
||
getScale(): number { | ||
return this.scale; | ||
getMetadata(): string { | ||
return this.metadata; | ||
} | ||
|
||
isVariable(): boolean { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Useful both on type and value. |
||
return this.metadata == "usize"; | ||
} | ||
} | ||
|
||
|
@@ -88,8 +89,8 @@ export class ManagedDecimalSignedValue extends TypedValue { | |
private readonly value: BigNumber; | ||
private readonly scale: number; | ||
|
||
constructor(value: BigNumber.Value, scale: number) { | ||
super(new ManagedDecimalType(scale)); | ||
constructor(value: BigNumber.Value, scale: number, isVariableDecimals: boolean = false) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Parameter name |
||
super(new ManagedDecimalSignedType(isVariableDecimals ? "usize" : scale)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also in |
||
this.value = new BigNumber(value); | ||
this.scale = scale; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ import { I64Type, NumericalValue, U16Type, U32Type, U32Value } from "./numerical | |
import { StringType } from "./string"; | ||
import { TypeExpressionParser } from "./typeExpressionParser"; | ||
import { NullType, PrimitiveType, Type } from "./types"; | ||
import { ManagedDecimalSignedType, ManagedDecimalType } from "./managedDecimal"; | ||
|
||
describe("test types", () => { | ||
let parser = new TypeExpressionParser(); | ||
|
@@ -63,6 +64,11 @@ describe("test types", () => { | |
parser.parse("Option<u32>").getFullyQualifiedName(), | ||
"multiversx:types:Option<multiversx:types:u32>", | ||
); | ||
assert.equal(new ManagedDecimalType("8").getFullyQualifiedName(), "multiversx:types:ManagedDecimal*8*"); | ||
assert.equal( | ||
new ManagedDecimalSignedType("8").getFullyQualifiedName(), | ||
"multiversx:types:ManagedDecimalSigned*8*", | ||
); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also test for variable / usize. |
||
}); | ||
|
||
it("types and values should have correct JavaScript class hierarchy", () => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,18 +44,26 @@ export class Type { | |
* Gets the fully qualified name of the type, to allow for better (efficient and non-ambiguous) type comparison within the custom typesystem. | ||
*/ | ||
getFullyQualifiedName(): string { | ||
return this.isGenericType() ? this.getFullNameForGeneric() : `multiversx:types:${this.getName()}`; | ||
return this.isGenericType() || this.hasMetadata() | ||
? this.getFullNameForGeneric() | ||
: `multiversx:types:${this.getName()}`; | ||
} | ||
|
||
private getFullNameForGeneric(): string { | ||
const hasTypeParameters = this.getTypeParameters.length > 0; | ||
const hasTypeParameters = this.getTypeParameters().length > 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
const joinedTypeParameters = hasTypeParameters | ||
? `${this.getTypeParameters() | ||
.map((type) => type.getFullyQualifiedName()) | ||
.join(", ")}` | ||
: ""; | ||
const baseName = `multiversx:types:${this.getName()}${joinedTypeParameters}`; | ||
return this.metadata !== undefined ? `${baseName}*${this.metadata}*` : baseName; | ||
let baseName = `multiversx:types:${this.getName()}`; | ||
if (hasTypeParameters) { | ||
baseName = `${baseName}<${joinedTypeParameters}>`; | ||
} | ||
if (this.metadata !== undefined) { | ||
baseName = `${baseName}*${this.metadata}*`; | ||
} | ||
return baseName; | ||
} | ||
|
||
hasExactClass(className: string): boolean { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeScript allows us to do this trick:
Can it be useful in our context?