-
Notifications
You must be signed in to change notification settings - Fork 5.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(std/io): add toReader & toWriter #5789
Conversation
What about |
Make sense. We can have the following methods.
|
Readable and Writeable stream are unfortunate complexities... |
Yeah, I know. But we should definitely support it. I made some changes to the return types, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have only one remark. @ry please review
cli/js/io.ts
Outdated
export function toWriter(dst: WritableStream): Writer & Closer { | ||
return new WritableStreamIOWriter(dst); | ||
} | ||
|
||
export function toReader(src: ReadableStream): Reader { | ||
return new ReadableStreamIOReader(src); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess those utils are useful but exposing them as Deno.toWriter()
and Deno.toReader()
doesn't seem to be a good idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My initial version was only for internal use but thought users will need a way to convert between Streams & Reader/Writer. Don't mind making them internal-only again.
cli/tests/unit/io_test.ts
Outdated
if (!chunk) return controller.close(); | ||
|
||
controller.enqueue(chunk); | ||
}, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great tests
cli/js/io.ts
Outdated
#reader: ReadableStreamDefaultReader; | ||
#buffer: Uint8Array | null; | ||
#encoder: TextEncoder; | ||
constructor(dst: ReadableStream) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't all of the ReadableStream
and WriteableStream
be ReadableStream<Uint8Array>
and WriteableStream<Uint8Array>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not used to setting types for streams and I missed it. Should be ReadableStream<Uint8Array | string>
and WriteableStream<Uint8Array>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add the following to the API:
function fromStreamReader(
streamReader: ReadableStreamDefaultReader<Uint8Array>,
): Deno.Reader {
const buffer = new Deno.Buffer(new Uint8Array(4096));
return {
async read(b: Uint8Array): Promise<number | null> {
if (buffer.empty()) {
const { done, value } = await streamReader.read();
if (done) {
return null;
}
await Deno.writeAll(buffer, value!);
}
return buffer.read(b);
},
};
}
function fromStreamWriter(
streamWriter: WritableStreamDefaultWriter<Uint8Array>,
): Deno.Writer {
return {
async write(b: Uint8Array): Promise<number> {
await streamWriter.write(b);
return b.length;
},
};
}
The original example will become:
const res = await fetch("http://example.com/file.bin");
const file = await Deno.open("/tmp/file.bin", { create: true, write: true });
await Deno.copy(Deno.fromStreamReader(res.body.getReader()), file);
file.close();
cli/js/lib.deno.ns.d.ts
Outdated
export function copy( | ||
src: Reader, | ||
dst: Writer, | ||
src: Reader | ReadableStream, | ||
dst: Writer | WritableStream, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, what is the intuition behind just copy()
supporting these and not every other IO function? This shouldn't be included in favour of just the conversion utilities.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wanted to do progressive changes instead of a massive PR (Initially it was meant to be an issue to discuss the API, but since I had some code that I was testing submitted a PR instead).
I'm good with only having utilities to convert from/to and leave Deno.copy
as is.
Now If we do only utilities, should they be in the core or in std?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have Deno.iter()
so I think these are candidates to be included in the CLI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's certainly handy for copy to take ReadableStream/WritableStream but in the interest of being conservative in our API changes, I think toReader and toWriter would solve the problem for now. Let's do the most minimal thing and expand on it later.
That is, I agree with @nayeemrmn, please undo this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm working on it and now I'm wondering whether we want to make the API take a ReadableStream
or a ReadableStreamDefaultReader / ReadableStreamBYOBReader
, the same goes for WritableStream
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The latter is the logical and minimal choice. It's only one more method call to use on a *ableStream
.
cc @kitsonk
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the reader/writer interfaces are what we want to use (the latter).
cli/js/lib.deno.ns.d.ts
Outdated
/** Turns a WritableStream into a Writer | ||
* @param dst The WritableStream to convert | ||
*/ | ||
export function toWriter(dst: WritableStream): Writer & Closer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New API additions should be unstable. Can you move these to lib.deno.unstable.d.ts ?
I'm not sure about the names in particular...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do!. Regarding the names, I'm open to suggestions.
@nayeemrmn suggested:
fromStreamReader
fromStreamWriter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great @marcosc90 - thanks for this patch - I just want to be careful about expanding our API. I think the most minimal thing is to add toWriter and toReader to the unstable API and not make any changes to the copy function.
Sounds good. I'll work on the modifications and update in the next couple of days. |
6a02d23
to
a0ab4eb
Compare
a0ab4eb
to
b904446
Compare
This is ready for review. Regarding the names, I don't care much, so whatever you prefer works for me.
or
Or any other alternative. |
@marcosc90 Maybe an even more minimal way to address this it to move toReader and toWriter into std. I understand that this would be less ergonomic - but it would allow us to experiment and iterate on these APIs before committing to adding them to the runtime. What do you think? |
I think it is a good idea, I asked about adding it to std here #5789 (comment) Should I place them in |
How about |
std/io/streams.ts seems reasonable to me |
d1d0df6
to
b67ea00
Compare
da72649
to
8429a37
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - thank you for seeing this one through @marcosc90
Replace arraybuffer new functionality exposed by `fromStreamReader` . see this PR: denoland/deno#5789 docs: https://deno.land/std/io/#fromstreamreader
Currently, we can do the following with fetch
res.body
If we make
Response
(#5787) spec-compliant the above code will stop working. I think it should still work.