Skip to content

refactor(io): replace Data with byte-oriented APIs#492

Draft
DzmingLi wants to merge 1 commit into
moonbitlang:mainfrom
DzmingLi:refactor/io-byte-oriented-api
Draft

refactor(io): replace Data with byte-oriented APIs#492
DzmingLi wants to merge 1 commit into
moonbitlang:mainfrom
DzmingLi:refactor/io-byte-oriented-api

Conversation

@DzmingLi

@DzmingLi DzmingLi commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • remove the sealed @io.Data abstraction
  • make Reader::read_all return owned Bytes
  • make Writer::write accept BytesView
  • add explicit UTF-8 and JSON helpers: read_all_text, read_all_json, write_text, and write_json
  • propagate Bytes/BytesView through the public fs, http, and process APIs and migrate the repository
  • validate Writer::write_once progress and reject zero-capacity BufferedWriters instead of allowing an infinite write loop

Motivation

Data currently serves two unrelated roles:

  1. an input conversion abstraction for Bytes, strings, and JSON; and
  2. an existential result from read_all, even though that result always contains Bytes.

The implementation calls this a hack itself. It also obscures ownership and allocation: receiving raw bytes is represented as &Data, while .text() and .json() can repeat conversions. Copying that shape into a synchronous I/O package would create another trait-object boundary instead of giving sync and async I/O the same byte-oriented core.

This draft makes the stream boundary explicit: raw I/O uses BytesView for input and owned Bytes for collected output. Text and JSON conversion remain convenient, but are named operations.

API migration

Before After
writer.write(bytes) writer.write(bytes)
writer.write("text") writer.write_text("text")
writer.write(json) writer.write_json(json)
reader.read_all().binary() reader.read_all()
reader.read_all().text() reader.read_all_text()
reader.read_all().json() reader.read_all_json()

If an old &Data result was saved and converted later, save the returned Bytes instead and call @utf8.decode / @json.parse explicitly. Do not replace multiple conversions with multiple read_all_* calls: each helper drains the reader.

Related public changes:

  • fs.read_file returns Bytes; fs.write_file accepts BytesView
  • HTTP request bodies accept BytesView; collected bodies return Bytes
  • process collect_* helpers return Bytes

This is an intentional breaking change. It also affects external Reader/Writer implementations and callers that previously passed strings or JSON directly to high-level byte-body APIs.

Design points for review

write remains the byte operation

This draft intentionally uses Writer::write(BytesView). Generic Show formatting belongs on a text sink/logger or behind an explicit text adapter, rather than occupying the primary binary I/O operation.

This supersedes only the Writer::write_data rename direction in #386. The independent Output::write_string change from that PR is not included here.

HTTP string interpolation

ServerConnection::write_string_interpolation changes from &@io.Data to &Show, matching ordinary string-interpolation display semantics. This is not mechanically equivalent for Bytes or Json: callers that want raw bytes or JSON wire format must use write or write_json explicitly. This behavior is called out for discussion rather than presented as compatibility-preserving.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant