Skip to content

Commit 8638fa7

Browse files
authored
Add more use-cases to byte size visitor (#839)
1 parent 8887fac commit 8638fa7

File tree

3 files changed

+611
-148
lines changed

3 files changed

+611
-148
lines changed

.changeset/nice-goats-grab.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@codama/visitors-core': patch
3+
---
4+
5+
Fix small bugs on the `getByteSizeVisitor` helper

packages/visitors-core/src/getByteSizeVisitor.ts

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isNode, isScalarEnum, REGISTERED_TYPE_NODE_KINDS, RegisteredTypeNode } from '@codama/nodes';
1+
import { CountNode, isNode, isScalarEnum, REGISTERED_TYPE_NODE_KINDS, RegisteredTypeNode } from '@codama/nodes';
22

33
import { extendVisitor } from './extendVisitor';
44
import { LinkableDictionary } from './LinkableDictionary';
@@ -12,6 +12,7 @@ import { visit, Visitor } from './visitor';
1212
export type ByteSizeVisitorKeys =
1313
| RegisteredTypeNode['kind']
1414
| 'accountNode'
15+
| 'constantValueNode'
1516
| 'definedTypeLinkNode'
1617
| 'definedTypeNode'
1718
| 'instructionArgumentNode'
@@ -35,11 +36,12 @@ export function getByteSizeVisitor(
3536
{
3637
keys: [
3738
...REGISTERED_TYPE_NODE_KINDS,
39+
'accountNode',
40+
'constantValueNode',
3841
'definedTypeLinkNode',
3942
'definedTypeNode',
40-
'accountNode',
41-
'instructionNode',
4243
'instructionArgumentNode',
44+
'instructionNode',
4345
],
4446
},
4547
);
@@ -53,11 +55,25 @@ export function getByteSizeVisitor(
5355
},
5456

5557
visitArrayType(node, { self }) {
56-
if (!isNode(node.count, 'fixedCountNode')) return null;
57-
const count = node.count.value;
58-
if (count === 0) return 0;
59-
const itemSize = visit(node.item, self);
60-
return itemSize !== null ? itemSize * count : null;
58+
return getArrayLikeSize(node.count, visit(node.item, self), self);
59+
},
60+
61+
visitConstantValue(node, { self }) {
62+
const typeSize = visit(node.type, self);
63+
if (typeSize !== null) return typeSize;
64+
if (isNode(node.value, 'bytesValueNode') && node.value.encoding === 'base16') {
65+
return Math.ceil(node.value.data.length / 2);
66+
}
67+
if (
68+
isNode(node.type, 'stringTypeNode') &&
69+
node.type.encoding === 'base16' &&
70+
isNode(node.value, 'stringValueNode')
71+
) {
72+
return Math.ceil(node.value.string.length / 2);
73+
}
74+
// Technically, we could still identify other fixed-size constants
75+
// but we'd need to import @solana/codecs to compute them.
76+
return null;
6177
},
6278

6379
visitDefinedType(node, { self }) {
@@ -117,12 +133,8 @@ export function getByteSizeVisitor(
117133
},
118134

119135
visitMapType(node, { self }) {
120-
if (!isNode(node.count, 'fixedCountNode')) return null;
121-
const count = node.count.value;
122-
if (count === 0) return 0;
123-
const keySize = visit(node.key, self);
124-
const valueSize = visit(node.value, self);
125-
return keySize !== null && valueSize !== null ? (keySize + valueSize) * count : null;
136+
const innerSize = sumSizes([visit(node.key, self), visit(node.value, self)]);
137+
return getArrayLikeSize(node.count, innerSize, self);
126138
},
127139

128140
visitNumberType(node) {
@@ -132,9 +144,17 @@ export function getByteSizeVisitor(
132144

133145
visitOptionType(node, { self }) {
134146
if (!node.fixed) return null;
135-
const prefixSize = visit(node.prefix, self) as number;
136-
const itemSize = visit(node.item, self);
137-
return itemSize !== null ? itemSize + prefixSize : null;
147+
return sumSizes([visit(node.prefix, self), visit(node.item, self)]);
148+
},
149+
150+
visitPostOffsetType(node, { self }) {
151+
const typeSize = visit(node.type, self);
152+
return node.strategy === 'padded' ? sumSizes([typeSize, node.offset]) : typeSize;
153+
},
154+
155+
visitPreOffsetType(node, { self }) {
156+
const typeSize = visit(node.type, self);
157+
return node.strategy === 'padded' ? sumSizes([typeSize, node.offset]) : typeSize;
138158
},
139159

140160
visitPublicKeyType() {
@@ -147,13 +167,28 @@ export function getByteSizeVisitor(
147167
},
148168

149169
visitSetType(node, { self }) {
150-
if (!isNode(node.count, 'fixedCountNode')) return null;
151-
const count = node.count.value;
152-
if (count === 0) return 0;
170+
return getArrayLikeSize(node.count, visit(node.item, self), self);
171+
},
172+
173+
visitZeroableOptionType(node, { self }) {
153174
const itemSize = visit(node.item, self);
154-
return itemSize !== null ? itemSize * count : null;
175+
if (!node.zeroValue) return itemSize;
176+
const zeroSize = visit(node.zeroValue, self);
177+
return zeroSize === itemSize ? itemSize : null;
155178
},
156179
}),
157180
v => recordNodeStackVisitor(v, stack),
158181
);
159182
}
183+
184+
function getArrayLikeSize(
185+
count: CountNode,
186+
innerSize: number | null,
187+
self: Visitor<number | null, ByteSizeVisitorKeys>,
188+
): number | null {
189+
if (innerSize === 0 && isNode(count, 'prefixedCountNode')) return visit(count.prefix, self);
190+
if (innerSize === 0) return 0;
191+
if (!isNode(count, 'fixedCountNode')) return null;
192+
if (count.value === 0) return 0;
193+
return innerSize !== null ? innerSize * count.value : null;
194+
}

0 commit comments

Comments
 (0)