Skip to content

Commit

Permalink
🐛 Fix the multiple same type in a tuple will lead to incorrect field …
Browse files Browse the repository at this point in the history
…length (#93)
  • Loading branch information
AlexV525 authored Jan 20, 2025
1 parent 46d0e5a commit 9b879ee
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 30 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ that can be found in the LICENSE file. -->

# Changelog

## 1.0.0-dev.35

- Fix the multiple same type in a tuple will lead to incorrect field length.

## 1.0.0-dev.34

- Handles IDL nested vec class encoding.
Expand Down
2 changes: 1 addition & 1 deletion packages/agent_dart/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: agent_dart
version: 1.0.0-dev.34
version: 1.0.0-dev.35

description: |
An agent library built for Internet Computer,
Expand Down
46 changes: 19 additions & 27 deletions packages/agent_dart_base/lib/candid/idl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:convert';
import 'dart:math' as math;
import 'dart:typed_data';

import 'package:collection/collection.dart';
import 'package:meta/meta.dart';

import '../agent/agent.dart';
Expand Down Expand Up @@ -1026,16 +1027,19 @@ class RecordClass extends ConstructType<Map> {

class TupleClass<T extends List> extends ConstructType<List> {
TupleClass(List<CType> components) : _components = components {
_fields = Map.from(_makeMap(components)).entries.toList();
_fields.sort(
(a, b) => idlLabelToId(a.key).toInt() - idlLabelToId(b.key).toInt(),
);
_fields = components.mapIndexed(_makeField).sorted(
(a, b) => idlLabelToId(a.key).toInt() - idlLabelToId(b.key).toInt(),
);
}

final List<CType> _components;

List<MapEntry> get fields => _fields;
late final List<MapEntry> _fields;
List<MapEntry<String, CType>> get fields => _fields;
late final List<MapEntry<String, CType>> _fields;

MapEntry<String, CType> _makeField(int index, CType component) {
return MapEntry('_${index}_', component);
}

@override
R accept<D, R>(Visitor<D, R> v, D d) {
Expand All @@ -1050,9 +1054,7 @@ class TupleClass<T extends List> extends ConstructType<List> {
// `>=` because tuples can be covariant when encoded.
return x.length >= _fields.length &&
_components
.asMap()
.entries
.map((t) => t.value.covariant(x[t.key]) ? 0 : 1)
.mapIndexed((index, value) => value.covariant(x[index]) ? 0 : 1)
.reduce((value, element) => value + element) ==
0;
}
Expand Down Expand Up @@ -1099,10 +1101,7 @@ class TupleClass<T extends List> extends ConstructType<List> {
);
}
final res = [];
for (final entry in tuple._components.asMap().entries) {
// [i, wireType]
final i = entry.key;
final wireType = entry.value;
for (final (i, wireType) in tuple._components.indexed) {
if (i >= _components.length) {
// skip value
wireType.decodeValue(x, wireType);
Expand Down Expand Up @@ -1134,12 +1133,6 @@ class TupleClass<T extends List> extends ConstructType<List> {
final fields = _fields.map((entry) => '${entry.key}:${entry.value.name}');
return "record {${fields.join('; ')}}";
}

Map<String, dynamic> _makeMap(List<CType> components) {
return {
for (final e in components) '_${components.indexOf(e)}_': e,
};
}
}

class VariantClass extends ConstructType<Map<String, dynamic>> {
Expand Down Expand Up @@ -1408,7 +1401,7 @@ class FuncClass extends ConstructType<List> {
'Arity mismatch',
);
}
return '(${types.asMap().entries.map((e) => e.value.valueToString(v[e.key])).join(', ')})';
return '(${types.mapIndexed((i, e) => e.valueToString(v[i])).join(', ')})';
}

@override
Expand Down Expand Up @@ -1868,22 +1861,21 @@ List idlDecode(List<CType> retTypes, Uint8List bytes) {
}
}

rawTable.asMap().forEach((i, entry) {
final t = buildType(entry);
for (final (i, e) in rawTable.indexed) {
final t = buildType(e);
table[i].fill(t);
});
}

final types = rawTypes.map((t) => getType(t)).toList();

final output = retTypes.asMap().entries.map((entry) {
final result = entry.value.decodeValue(b, types[entry.key]);
return result;
}).toList();
final output =
retTypes.mapIndexed((i, e) => e.decodeValue(b, types[i])).toList();

// Skip unused values.
for (int ind = retTypes.length; ind < types.length; ind++) {
types[ind].decodeValue(b, types[ind]);
}

if (b.buffer.isNotEmpty) {
throw StateError('Unexpected left-over bytes.');
}
Expand Down
2 changes: 1 addition & 1 deletion packages/agent_dart_base/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: agent_dart_base
version: 1.0.0-dev.34
version: 1.0.0-dev.35

description: The Dart plugin that bridges Rust implementation for agent_dart.
repository: https://github.com/AstroxNetwork/agent_dart
Expand Down
13 changes: 13 additions & 0 deletions packages/agent_dart_base/test/candid/idl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,19 @@ void idlTest() {
]),
throwsA(isError<ArgumentError>()),
);
expect(
IDL.encode(
[
IDL.Tuple([IDL.Text, IDL.Text])
],
[
['a', 'b']
],
),
Uint8List.fromList(
[68, 73, 68, 76, 1, 108, 2, 0, 113, 1, 113, 1, 0, 1, 97, 1, 98],
),
);
});

test('IDL encoding (arraybuffer)', () {
Expand Down
2 changes: 1 addition & 1 deletion packages/agent_dart_ffi/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: agent_dart_ffi
version: 1.0.0-dev.34
version: 1.0.0-dev.35

description: The FFI plugin that bridges Rust implementation for agent_dart.
repository: https://github.com/AstroxNetwork/agent_dart
Expand Down

0 comments on commit 9b879ee

Please sign in to comment.