11import { describe , expect , it } from 'vitest'
2-
32import { makeMap , mapGet , mapSet } from './map.js'
43import {
54 append ,
65 appendSlice ,
6+ appendZero ,
7+ appendZeros ,
78 arrayToSlice ,
89 byteSliceHint ,
910 bytesToString ,
1011 copy ,
12+ goSlice ,
1113 indexString ,
1214 len ,
1315 makeSlice ,
@@ -18,6 +20,7 @@ import {
1820 stringEqual ,
1921 stringToBytes ,
2022} from './slice.js'
23+ import { markAsStructValue } from './type.js'
2124
2225describe ( 'rune to string encoding (Go string(rune) semantics)' , ( ) => {
2326 it ( 'preserves astral-plane runes above U+FFFF' , ( ) => {
@@ -97,6 +100,63 @@ describe('destination-independent byte specialization', () => {
97100 } )
98101} )
99102
103+ describe ( 'append spare capacity' , ( ) => {
104+ class item {
105+ value = 0
106+ }
107+
108+ it ( 'zero-initializes primitive elements exposed by reslicing' , ( ) => {
109+ let values = append < number > ( null , 1 )
110+ values = append ( values , 2 )
111+ values = append ( values , 3 )
112+
113+ expect ( goSlice ( values , undefined , 4 ) [ 3 ] ) . toBe ( 0 )
114+ } )
115+
116+ it ( 'zero-initializes struct elements exposed by reslicing' , ( ) => {
117+ const zeroHint = appendZero ( ( ) => markAsStructValue ( new item ( ) ) )
118+ let values = append < item > ( null , markAsStructValue ( new item ( ) ) , zeroHint )
119+ values = append ( values , markAsStructValue ( new item ( ) ) , zeroHint )
120+ values = append ( values , markAsStructValue ( new item ( ) ) , zeroHint )
121+
122+ const zero = goSlice ( values , undefined , 4 ) [ 3 ]
123+ expect ( zero ) . toBeInstanceOf ( item )
124+ expect ( zero . value ) . toBe ( 0 )
125+ } )
126+
127+ it ( 'creates independent struct zeros for every spare slot' , ( ) => {
128+ const zeroHint = appendZero ( ( ) => markAsStructValue ( new item ( ) ) )
129+ let values = append < item > ( null , markAsStructValue ( new item ( ) ) , zeroHint )
130+ for ( let i = 0 ; i < 4 ; i ++ ) {
131+ values = append ( values , markAsStructValue ( new item ( ) ) , zeroHint )
132+ }
133+
134+ const expanded = goSlice ( values , undefined , 8 )
135+ expanded [ 5 ] . value = 7
136+ expect ( expanded [ 6 ] . value ) . toBe ( 0 )
137+ expect ( expanded [ 5 ] ) . not . toBe ( expanded [ 6 ] )
138+ } )
139+
140+ it ( 'zero-initializes appendSlice spare capacity from a static hint' , ( ) => {
141+ const dynamic = markAsStructValue ( new item ( ) )
142+ const source : ( item | null ) [ ] = [ dynamic ]
143+ let values = appendSlice < item | null > ( null , source , appendZeros . nil )
144+ values = appendSlice ( values , source , appendZeros . nil )
145+ values = appendSlice ( values , source , appendZeros . nil )
146+
147+ expect ( goSlice ( values , undefined , 4 ) [ 3 ] ) . toBeNull ( )
148+ } )
149+
150+ it ( 'uses the static interface zero instead of the dynamic element type' , ( ) => {
151+ const dynamic = markAsStructValue ( new item ( ) )
152+ let values = append < item | null > ( null , dynamic , appendZeros . nil )
153+ values = append ( values , dynamic , appendZeros . nil )
154+ values = append ( values , dynamic , appendZeros . nil )
155+
156+ expect ( goSlice ( values , undefined , 4 ) [ 3 ] ) . toBeNull ( )
157+ } )
158+ } )
159+
100160describe ( 'builtin string byte representation' , ( ) => {
101161 it ( 'appends large byte slices without JavaScript argument spreading' , ( ) => {
102162 const dst = new Uint8Array ( 0 )
0 commit comments