1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-30 16:40:57 -05:00
denoland-deno/ext/node/polyfills/_fs/_fs_readv.ts
Nathan Whitaker 7ad76fd453
fix(ext/node): Add fs.readv, fs.readvSync (#23166)
Part of #18218.

Implements `fs.readv` and `fs.readvSync` and enables the corresponding
`node_compat` tests.
2024-04-01 20:42:49 -07:00

130 lines
3.1 KiB
TypeScript

// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials
import {
ERR_INVALID_ARG_TYPE,
type ErrnoException,
} from "ext:deno_node/internal/errors.ts";
import {
getValidatedFd,
validateBufferArray,
} from "ext:deno_node/internal/fs/utils.mjs";
import { maybeCallback } from "ext:deno_node/_fs/_fs_common.ts";
import { validateInteger } from "ext:deno_node/internal/validators.mjs";
import * as io from "ext:deno_io/12_io.js";
import * as fs from "ext:deno_fs/30_fs.js";
type Callback = (
err: ErrnoException | null,
bytesRead: number,
buffers: readonly ArrayBufferView[],
) => void;
export function readv(
fd: number,
buffers: readonly ArrayBufferView[],
callback: Callback,
): void;
export function readv(
fd: number,
buffers: readonly ArrayBufferView[],
position: number | Callback,
callback?: Callback,
): void {
if (typeof fd !== "number") {
throw new ERR_INVALID_ARG_TYPE("fd", "number", fd);
}
fd = getValidatedFd(fd);
validateBufferArray(buffers);
const cb = maybeCallback(callback || position) as Callback;
let pos: number | null = null;
if (typeof position === "number") {
validateInteger(position, "position", 0);
pos = position;
}
if (buffers.length === 0) {
process.nextTick(cb, null, 0, buffers);
return;
}
const innerReadv = async (
fd: number,
buffers: readonly ArrayBufferView[],
position: number | null,
) => {
if (typeof position === "number") {
await fs.seek(fd, position, io.SeekMode.Start);
}
let readTotal = 0;
let readInBuf = 0;
let bufIdx = 0;
let buf = buffers[bufIdx];
while (bufIdx < buffers.length) {
const nread = await io.read(fd, buf);
if (nread === null) {
break;
}
readInBuf += nread;
if (readInBuf === buf.byteLength) {
readTotal += readInBuf;
readInBuf = 0;
bufIdx += 1;
buf = buffers[bufIdx];
}
}
readTotal += readInBuf;
return readTotal;
};
innerReadv(fd, buffers, pos).then(
(numRead) => {
cb(null, numRead, buffers);
},
(err) => cb(err, -1, buffers),
);
}
export function readvSync(
fd: number,
buffers: readonly ArrayBufferView[],
position: number | null = null,
): number {
if (typeof fd !== "number") {
throw new ERR_INVALID_ARG_TYPE("fd", "number", fd);
}
fd = getValidatedFd(fd);
validateBufferArray(buffers);
if (buffers.length === 0) {
return 0;
}
if (typeof position === "number") {
validateInteger(position, "position", 0);
fs.seekSync(fd, position, io.SeekMode.Start);
}
let readTotal = 0;
let readInBuf = 0;
let bufIdx = 0;
let buf = buffers[bufIdx];
while (bufIdx < buffers.length) {
const nread = io.readSync(fd, buf);
if (nread === null) {
break;
}
readInBuf += nread;
if (readInBuf === buf.byteLength) {
readTotal += readInBuf;
readInBuf = 0;
bufIdx += 1;
buf = buffers[bufIdx];
}
}
readTotal += readInBuf;
return readTotal;
}