@@ -59,22 +59,12 @@ pub fn readv(sd: Stream_Device, bytes_vec: []const []u8) ReadError!usize {
5959 return readv_fn (sd .ptr , bytes_vec );
6060}
6161
62- pub const Reader = std .io .Reader (Stream_Device , ReadError , reader_read );
63- pub fn reader (sd : Stream_Device ) Reader {
64- return .{ .context = sd };
62+ pub fn writer (self : Stream_Device , buf : []u8 ) Writer {
63+ return .init (self , buf );
6564}
6665
67- fn reader_read (sd : Stream_Device , buf : []u8 ) ReadError ! usize {
68- return sd .read (buf );
69- }
70-
71- pub const Writer = std .io .Reader (Stream_Device , WriteError , writer_write );
72- pub fn writer (sd : Stream_Device ) Writer {
73- return .{ .context = sd };
74- }
75-
76- fn writer_write (sd : Stream_Device , buf : []const u8 ) WriteError ! usize {
77- return sd .write (buf );
66+ pub fn reader (self : Stream_Device , buf : []u8 ) Reader {
67+ return .init (self , buf );
7868}
7969
8070pub const VTable = struct {
@@ -84,6 +74,105 @@ pub const VTable = struct {
8474 readv_fn : ? * const fn (* anyopaque , datagram : []const []u8 ) ReadError ! usize ,
8575};
8676
77+ /// microzig already has this function in SliceVector, but no other base driver include microzig as a dependency
78+ /// so we duplicate it here for now
79+ fn byte_sum (data : []const []const u8 ) usize {
80+ var sum : usize = 0 ;
81+ for (data ) | bytes | {
82+ sum += bytes .len ;
83+ }
84+ return sum ;
85+ }
86+
87+ pub const Writer = struct {
88+ dev : Stream_Device ,
89+ interface : std.Io.Writer ,
90+ err : ? WriteError = null ,
91+
92+ fn drain (w : * std.Io.Writer , data : []const []const u8 , splat : usize ) std.Io.Writer.Error ! usize {
93+ const wt : * Writer = @alignCast (@fieldParentPtr ("interface" , w ));
94+ const total_size = byte_sum (data );
95+ var ret : usize = 0 ;
96+
97+ const n = wt .dev .write (w .buffered ()) catch | err | {
98+ wt .err = err ;
99+ return error .WriteFailed ;
100+ };
101+ _ = w .consume (n );
102+
103+ ret = wt .dev .writev (data ) catch | err | {
104+ wt .err = err ;
105+ return error .WriteFailed ;
106+ };
107+
108+ // NOTE: maybe check if ret is 0 across multiple calls to detect broken stream?
109+ // check if we wrote everything we wanted before splatting
110+ if (ret != total_size ) {
111+ return ret ;
112+ }
113+
114+ const pattern = data [data .len - 1 ];
115+ for (0.. splat ) | _ | {
116+ const s_len = wt .dev .write (pattern ) catch | err | {
117+ wt .err = err ;
118+ return error .WriteFailed ;
119+ };
120+ ret += s_len ;
121+ if (s_len < pattern .len ) break ; // if the previous pattern was not fully written, break the loop
122+ }
123+
124+ return ret ;
125+ }
126+
127+ pub fn init (dev : Stream_Device , buf : []u8 ) Writer {
128+ return Writer {
129+ .dev = dev ,
130+ .interface = .{
131+ .buffer = buf ,
132+ .vtable = &.{
133+ .drain = drain ,
134+ },
135+ },
136+ };
137+ }
138+ };
139+
140+ pub const Reader = struct {
141+ dev : Stream_Device ,
142+ interface : std.Io.Reader ,
143+ err : ? ReadError = null ,
144+
145+ fn stream (r : * std.Io.Reader , w : * std.Io.Writer , limit : std.Io.Limit ) std.Io.Reader.StreamError ! usize {
146+ const rd : * Reader = @alignCast (@fieldParentPtr ("interface" , r ));
147+ const w_buf = limit .slice (try w .writableSliceGreedy (1 ));
148+
149+ const n = rd .dev .read (w_buf ) catch | err | {
150+ rd .err = err ;
151+ return error .ReadFailed ;
152+ };
153+
154+ // NOTE: should we treat 0 as an EOF or check if 0 across multiple calls before returning EOF?
155+ if (n == 0 ) return error .EndOfStream ;
156+
157+ w .advance (n );
158+ return n ;
159+ }
160+
161+ pub fn init (dev : Stream_Device , buf : []u8 ) Reader {
162+ return Reader {
163+ .dev = dev ,
164+ .interface = .{
165+ .buffer = buf ,
166+ .seek = 0 ,
167+ .end = 0 ,
168+ .vtable = &.{
169+ .stream = stream ,
170+ },
171+ },
172+ };
173+ }
174+ };
175+
87176/// A device implementation that can be used to write unit tests for datagram devices.
88177pub const Test_Device = struct {
89178 input : ? std .io .FixedBufferStream ([]const u8 ),
0 commit comments