@@ -184,6 +184,27 @@ impl<'instance> BufferMut<'instance> {
184184 }
185185}
186186
187+ impl std:: io:: Write for BufferMut < ' _ > {
188+ fn write ( & mut self , buf : & [ u8 ] ) -> std:: io:: Result < usize > {
189+ let last_write = ( * self . write_ptr ) as usize ;
190+ let free = self . buffer . len ( ) - last_write;
191+ let n = buf. len ( ) . min ( free) ;
192+ if n == 0 && !buf. is_empty ( ) {
193+ return Err ( std:: io:: Error :: new (
194+ std:: io:: ErrorKind :: WriteZero ,
195+ "buffer full" ,
196+ ) ) ;
197+ }
198+ self . buffer [ last_write..last_write + n] . copy_from_slice ( & buf[ ..n] ) ;
199+ * self . write_ptr = ( last_write + n) as u32 ;
200+ Ok ( n)
201+ }
202+
203+ fn flush ( & mut self ) -> std:: io:: Result < ( ) > {
204+ Ok ( ( ) )
205+ }
206+ }
207+
187208#[ inline( always) ]
188209pub ( crate ) fn compute_ptr < T > ( ptr : * mut T , linear_mem_space : & WasmLinearMem ) -> * mut T {
189210 let mem_start_ptr = linear_mem_space. start_ptr ;
@@ -200,13 +221,15 @@ fn from_raw_builder<'a>(builder_ptr: *mut BufferBuilder, mem: WasmLinearMem) ->
200221 unsafe {
201222 #[ cfg( feature = "trace" ) ]
202223 {
203- let contract_mem = std:: slice:: from_raw_parts ( mem. start_ptr , mem. size as usize ) ;
204- tracing:: trace!(
205- "*mut BufferBuilder <- offset: {}; in mem: {:?}" ,
206- builder_ptr as usize ,
207- & contract_mem[ builder_ptr as usize
208- ..builder_ptr as usize + std:: mem:: size_of:: <BufferBuilder >( ) ]
209- ) ;
224+ if !mem. start_ptr . is_null ( ) && mem. size > 0 {
225+ let contract_mem = std:: slice:: from_raw_parts ( mem. start_ptr , mem. size as usize ) ;
226+ tracing:: trace!(
227+ "*mut BufferBuilder <- offset: {}; in mem: {:?}" ,
228+ builder_ptr as usize ,
229+ & contract_mem[ builder_ptr as usize
230+ ..builder_ptr as usize + std:: mem:: size_of:: <BufferBuilder >( ) ]
231+ ) ;
232+ }
210233 // use std::{fs::File, io::Write};
211234 // let mut f = File::create(std::env::temp_dir().join("dump.mem")).unwrap();
212235 // f.write_all(contract_mem).unwrap();
@@ -340,6 +363,94 @@ fn __frnt__initiate_buffer(capacity: u32) -> i64 {
340363 buffer as i64
341364}
342365
366+ #[ cfg( test) ]
367+ mod test_io_write {
368+ use super :: * ;
369+ use std:: io:: Write ;
370+
371+ /// Create a BufferMut backed by host memory (no WASM runtime needed).
372+ /// Uses `__frnt__initiate_buffer` which allocates in host memory during tests,
373+ /// and a null-base WasmLinearMem so compute_ptr is a no-op on absolute pointers.
374+ unsafe fn host_buffer_mut ( capacity : u32 ) -> BufferMut < ' static > {
375+ let builder_ptr = __frnt__initiate_buffer ( capacity) as * mut BufferBuilder ;
376+ let linear_mem = WasmLinearMem {
377+ start_ptr : std:: ptr:: null ( ) ,
378+ size : 0 ,
379+ } ;
380+ BufferMut :: from_ptr ( builder_ptr, linear_mem)
381+ }
382+
383+ /// Call std::io::Write::write (not BufferMut::write which has different signature)
384+ fn io_write ( buf : & mut BufferMut < ' _ > , data : & [ u8 ] ) -> std:: io:: Result < usize > {
385+ Write :: write ( buf, data)
386+ }
387+
388+ #[ test]
389+ fn write_trait_basic ( ) {
390+ let mut buf = unsafe { host_buffer_mut ( 32 ) } ;
391+ let n = io_write ( & mut buf, b"hello" ) . unwrap ( ) ;
392+ assert_eq ! ( n, 5 ) ;
393+ assert_eq ! ( buf. read_bytes( 5 ) , b"hello" ) ;
394+ }
395+
396+ #[ test]
397+ fn write_trait_fills_exactly ( ) {
398+ let mut buf = unsafe { host_buffer_mut ( 4 ) } ;
399+ let n = io_write ( & mut buf, b"abcd" ) . unwrap ( ) ;
400+ assert_eq ! ( n, 4 ) ;
401+ assert_eq ! ( buf. read_bytes( 4 ) , b"abcd" ) ;
402+ }
403+
404+ #[ test]
405+ fn write_trait_partial_when_near_full ( ) {
406+ let mut buf = unsafe { host_buffer_mut ( 4 ) } ;
407+ io_write ( & mut buf, b"ab" ) . unwrap ( ) ;
408+ // Only 2 bytes free, writing 3 should write 2
409+ let n = io_write ( & mut buf, b"xyz" ) . unwrap ( ) ;
410+ assert_eq ! ( n, 2 ) ;
411+ assert_eq ! ( buf. read_bytes( 4 ) , b"abxy" ) ;
412+ }
413+
414+ #[ test]
415+ fn write_trait_error_when_full ( ) {
416+ let mut buf = unsafe { host_buffer_mut ( 2 ) } ;
417+ io_write ( & mut buf, b"ab" ) . unwrap ( ) ;
418+ let err = io_write ( & mut buf, b"c" ) . unwrap_err ( ) ;
419+ assert_eq ! ( err. kind( ) , std:: io:: ErrorKind :: WriteZero ) ;
420+ }
421+
422+ #[ test]
423+ fn write_trait_empty_slice_ok ( ) {
424+ let mut buf = unsafe { host_buffer_mut ( 4 ) } ;
425+ let n = io_write ( & mut buf, b"" ) . unwrap ( ) ;
426+ assert_eq ! ( n, 0 ) ;
427+ }
428+
429+ #[ test]
430+ fn write_all_trait ( ) {
431+ let mut buf = unsafe { host_buffer_mut ( 16 ) } ;
432+ buf. write_all ( b"hello world" ) . unwrap ( ) ;
433+ assert_eq ! ( buf. read_bytes( 11 ) , b"hello world" ) ;
434+ }
435+
436+ #[ test]
437+ fn write_all_insufficient_space ( ) {
438+ let mut buf = unsafe { host_buffer_mut ( 4 ) } ;
439+ let err = buf. write_all ( b"hello" ) . unwrap_err ( ) ;
440+ assert_eq ! ( err. kind( ) , std:: io:: ErrorKind :: WriteZero ) ;
441+ }
442+
443+ #[ test]
444+ fn bincode_serialize_into ( ) {
445+ let data: Vec < u32 > = vec ! [ 1 , 2 , 3 , 4 , 5 ] ;
446+ let size = bincode:: serialized_size ( & data) . unwrap ( ) as usize ;
447+ let mut buf = unsafe { host_buffer_mut ( size as u32 ) } ;
448+ bincode:: serialize_into ( & mut buf, & data) . unwrap ( ) ;
449+ let result: Vec < u32 > = bincode:: deserialize ( buf. read_bytes ( size) ) . unwrap ( ) ;
450+ assert_eq ! ( result, data) ;
451+ }
452+ }
453+
343454#[ cfg( all( test, any( unix, windows) , feature = "wasmer-tests" ) ) ]
344455mod test {
345456 use super :: * ;
0 commit comments