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
33import { extendVisitor } from './extendVisitor' ;
44import { LinkableDictionary } from './LinkableDictionary' ;
@@ -12,6 +12,7 @@ import { visit, Visitor } from './visitor';
1212export 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