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

Non-breaking change: add support for "counted-variadic" #323

Merged
merged 10 commits into from
Aug 31, 2023

Conversation

andreibancioiu
Copy link
Contributor

@andreibancioiu andreibancioiu commented Aug 29, 2023

Should fix: #316.

ArgsSerializer and the type inference system have been adjusted to handle counted-variadic arguments, as well. Though, note that (due to constraints brought by the current implementation of the type inference system) counted variadic arguments must be explicitly typed when calling contract methods. E.g.

contract.methods.doSomething([42, VariadicValue.fromItemsCounted(...), "foobar"]);

Or:

contract.methods.doSomething([42, new VariadicValue(...), "foobar"]);

In order to create a counted-variadic type, pass true as the second parameter for the VariadicType constructor. E.g.

const type = new VariadicType(..., true);

@andreibancioiu andreibancioiu self-assigned this Aug 29, 2023
function repackNonCountedVariadicParameters(args: any[], endpoint: EndpointDefinition) {
let parameters = endpoint.input;

// TODO: Remove after first review. Temporarily left this way to make the review easier.
Copy link
Contributor Author

@andreibancioiu andreibancioiu Aug 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Remove if (true) after first review! ⚠️

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

return this.createFromItems(items, false);
}

static fromItemsCounted(...items: TypedValue[]): VariadicValue {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New utility function.

@@ -76,11 +74,11 @@ describe("test mapper", () => {
assert.deepEqual(mappedType, new ArrayVecType(size, typeParameter));
}

function testMapping(expression: string, constructor: TypeConstructor, typeParameters: Type[] = []) {
function testMapping(expression: string, expectedType: Type) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a refactoring, simplification in this tests file.

@andreibancioiu andreibancioiu marked this pull request as ready for review August 31, 2023 06:47
typedValues.push(readValue(type.getFirstTypeParameter()));
}
} else {
while (!hasReachedTheEnd()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-counted variadic arguments (regular variadic arguments) can only be at the tail of the arguments.


if (variadicType.isCounted) {
const countValue = new U32Value(valueAsVariadic.getItems().length);
buffers.push(self.codec.encodeTopLevel(countValue));
Copy link
Contributor Author

@andreibancioiu andreibancioiu Aug 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@count@var1@var2@var3.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the variadic arg handling can be pulled into a function so we have less complexity in the if/else branches.

Q: do you like the else if {} approach better? Since every branch returns, we could also have less indenting doing:

if (condition) {
  ...
  return result
}

if (condition2) {
  ...
  return result2;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, fixed. Extracted handling into separate (though "nested") functions. Also re-organized branches for less indenting 👍

const endpoint = new EndpointDefinition("foo", inputParameters, [], endpointModifiers);

// Implicit counted-variadic (not supported).
assert.throws(() => NativeSerializer.nativeToTypedValues([8, 9, 10, "a", "b", "c"], endpoint), ErrInvalidArgument);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot be supported in the current implementation of the NativeSerializer, due to args-packing ambiguity.

Comment on lines +72 to +73
VariadicValue.fromItemsCounted(new U32Value(8), new U32Value(9), new U32Value(10)),
VariadicValue.fromItemsCounted(BytesValue.fromUTF8("a"), BytesValue.fromUTF8("b"), BytesValue.fromUTF8("c"))
Copy link
Contributor Author

@andreibancioiu andreibancioiu Aug 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible to have multiple counted variadic arguments (users are required to pass them in the explicitly typed form).

if (hasNonCountedVariadicParameter(endpoint)) {
args = repackNonCountedVariadicParameters(args, endpoint);
} else {
// Repacking makes sense (it's possible) only for regular, non-counted variadic parameters.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No repacking: there are no regular (non-counted) variadic parameters.

function toVariadicValue(native: any, type: Type, errorContext: ArgumentErrorContext): TypedValue {
function toVariadicValue(native: any, type: VariadicType, errorContext: ArgumentErrorContext): TypedValue {
if (type.isCounted) {
throw new ErrInvalidArgument(`Counted variadic arguments must be explicitly typed. E.g. use "VariadicValue.fromItemsCounted()" or "new VariadicValue()"`);
Copy link
Contributor Author

@andreibancioiu andreibancioiu Aug 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other words, the type inference system won't perform any type inference for counted-variadic.

@@ -2,6 +2,20 @@ import { Type, TypeCardinality, TypedValue, TypePlaceholder } from "./types";

export class VariadicType extends Type {
static ClassName = "VariadicType";
public readonly isCounted: boolean;

constructor(typeParameter: Type, isCounted: boolean = false) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theoretically, not a breaking change.

@andreibancioiu andreibancioiu changed the title Add support for "counted-variadic" Non-breaking change: add support for "counted-variadic" Aug 31, 2023
@andreibancioiu
Copy link
Contributor Author

Related (examples): multiversx/mx-sdk-js-examples#27.

dragos-rebegea
dragos-rebegea previously approved these changes Aug 31, 2023
@andreibancioiu andreibancioiu merged commit d8b4893 into main Aug 31, 2023
1 check passed
@andreibancioiu andreibancioiu deleted the counted-variadic branch August 31, 2023 16:00
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.

Add support for counted-variadic type in ABI parsing
3 participants