mirror of
https://github.com/denoland/std.git
synced 2024-11-21 12:40:03 +00:00
BREAKING(io): remove readRange[Sync]()
(#6049)
BREAKING(io/unstable): remove `readRange()`
This commit is contained in:
parent
eb064eba09
commit
3500797dcb
@ -14,7 +14,6 @@
|
||||
"./read-delim": "./read_delim.ts",
|
||||
"./read-int": "./read_int.ts",
|
||||
"./read-long": "./read_long.ts",
|
||||
"./read-range": "./read_range.ts",
|
||||
"./read-short": "./read_short.ts",
|
||||
"./read-string-delim": "./read_string_delim.ts",
|
||||
"./reader-from-stream-reader": "./reader_from_stream_reader.ts",
|
||||
|
@ -27,7 +27,6 @@ export * from "./read_all.ts";
|
||||
export * from "./read_delim.ts";
|
||||
export * from "./read_int.ts";
|
||||
export * from "./read_long.ts";
|
||||
export * from "./read_range.ts";
|
||||
export * from "./read_short.ts";
|
||||
export * from "./read_string_delim.ts";
|
||||
export * from "./reader_from_stream_reader.ts";
|
||||
|
127
io/read_range.ts
127
io/read_range.ts
@ -1,127 +0,0 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { copy as copyBytes } from "@std/bytes/copy";
|
||||
import type { Reader, ReaderSync, Seeker, SeekerSync } from "./types.ts";
|
||||
|
||||
const DEFAULT_BUFFER_SIZE = 32 * 1024;
|
||||
|
||||
/**
|
||||
* The range of bytes to read from a file or other resource that is readable.
|
||||
*
|
||||
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
|
||||
*/
|
||||
export interface ByteRange {
|
||||
/** The 0 based index of the start byte for a range. */
|
||||
start: number;
|
||||
|
||||
/** The 0 based index of the end byte for a range, which is inclusive. */
|
||||
end: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a range of bytes from a file or other resource that is readable and
|
||||
* seekable. The range start and end are inclusive of the bytes within that
|
||||
* range.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertEquals } from "@std/assert";
|
||||
* import { readRange } from "@std/io/read-range";
|
||||
*
|
||||
* // Read the first 10 bytes of a file
|
||||
* const file = await Deno.open("example.txt", { read: true });
|
||||
* const bytes = await readRange(file, { start: 0, end: 9 });
|
||||
* assertEquals(bytes.length, 10);
|
||||
* ```
|
||||
*
|
||||
* @param r The reader to read from
|
||||
* @param range The range of bytes to read
|
||||
* @returns The bytes read
|
||||
*
|
||||
* @deprecated Use
|
||||
* {@linkcode https://jsr.io/@std/streams/doc/byte-slice-stream/~/ByteSliceStream | ByteSliceStream}
|
||||
* instead. This will be removed in 0.225.0.
|
||||
*/
|
||||
export async function readRange(
|
||||
r: Reader & Seeker,
|
||||
range: ByteRange,
|
||||
): Promise<Uint8Array> {
|
||||
// byte ranges are inclusive, so we have to add one to the end
|
||||
let length = range.end - range.start + 1;
|
||||
if (length <= 0) {
|
||||
throw new RangeError("Byte range start cannot be larger than end");
|
||||
}
|
||||
await r.seek(range.start, Deno.SeekMode.Start);
|
||||
const result = new Uint8Array(length);
|
||||
let off = 0;
|
||||
while (length) {
|
||||
const p = new Uint8Array(Math.min(length, DEFAULT_BUFFER_SIZE));
|
||||
const nread = await r.read(p);
|
||||
if (nread === null) {
|
||||
throw new Error("Unexpected EOF reach while reading a range");
|
||||
}
|
||||
if (nread === 0) {
|
||||
throw new Error("Unexpected read of 0 bytes while reading a range");
|
||||
}
|
||||
copyBytes(p, result, off);
|
||||
off += nread;
|
||||
length -= nread;
|
||||
if (length < 0) {
|
||||
throw new Error("Unexpected length remaining after reading range");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a range of bytes synchronously from a file or other resource that is
|
||||
* readable and seekable. The range start and end are inclusive of the bytes
|
||||
* within that range.
|
||||
*
|
||||
* @example Usage
|
||||
* ```ts ignore
|
||||
* import { assertEquals } from "@std/assert";
|
||||
* import { readRangeSync } from "@std/io/read-range";
|
||||
*
|
||||
* // Read the first 10 bytes of a file
|
||||
* const file = Deno.openSync("example.txt", { read: true });
|
||||
* const bytes = readRangeSync(file, { start: 0, end: 9 });
|
||||
* assertEquals(bytes.length, 10);
|
||||
* ```
|
||||
*
|
||||
* @param r The reader to read from
|
||||
* @param range The range of bytes to read
|
||||
* @returns The bytes read
|
||||
*
|
||||
* @deprecated This will be removed in 1.0.0. Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
|
||||
*/
|
||||
export function readRangeSync(
|
||||
r: ReaderSync & SeekerSync,
|
||||
range: ByteRange,
|
||||
): Uint8Array {
|
||||
// byte ranges are inclusive, so we have to add one to the end
|
||||
let length = range.end - range.start + 1;
|
||||
if (length <= 0) {
|
||||
throw new RangeError("Byte range start cannot be larger than end");
|
||||
}
|
||||
r.seekSync(range.start, Deno.SeekMode.Start);
|
||||
const result = new Uint8Array(length);
|
||||
let off = 0;
|
||||
while (length) {
|
||||
const p = new Uint8Array(Math.min(length, DEFAULT_BUFFER_SIZE));
|
||||
const nread = r.readSync(p);
|
||||
if (nread === null) {
|
||||
throw new Error("Unexpected EOF reach while reading a range");
|
||||
}
|
||||
if (nread === 0) {
|
||||
throw new Error("Unexpected read of 0 bytes while reading a range");
|
||||
}
|
||||
copyBytes(p, result, off);
|
||||
off += nread;
|
||||
length -= nread;
|
||||
if (length < 0) {
|
||||
throw new Error("Unexpected length remaining after reading range");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { copy } from "@std/bytes/copy";
|
||||
import { assert, assertEquals, assertRejects, assertThrows } from "@std/assert";
|
||||
import { readRange, readRangeSync } from "./read_range.ts";
|
||||
import type {
|
||||
Closer,
|
||||
Reader,
|
||||
ReaderSync,
|
||||
Seeker,
|
||||
SeekerSync,
|
||||
} from "./types.ts";
|
||||
|
||||
// N controls how many iterations of certain checks are performed.
|
||||
const N = 100;
|
||||
let testBytes: Uint8Array | undefined;
|
||||
|
||||
export function init() {
|
||||
if (testBytes === undefined) {
|
||||
testBytes = new Uint8Array(N);
|
||||
for (let i = 0; i < N; i++) {
|
||||
testBytes[i] = "a".charCodeAt(0) + (i % 26);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MockFile implements Seeker, SeekerSync, Reader, ReaderSync, Closer {
|
||||
#buf: Uint8Array;
|
||||
#closed = false;
|
||||
#offset = 0;
|
||||
|
||||
get closed() {
|
||||
return this.#closed;
|
||||
}
|
||||
|
||||
constructor(buf: Uint8Array) {
|
||||
this.#buf = buf;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.#closed = true;
|
||||
}
|
||||
|
||||
read(p: Uint8Array): Promise<number | null> {
|
||||
if (this.#offset >= this.#buf.length) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
const nread = Math.min(p.length, 16_384, this.#buf.length - this.#offset);
|
||||
if (nread === 0) {
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
copy(this.#buf.subarray(this.#offset, this.#offset + nread), p);
|
||||
this.#offset += nread;
|
||||
return Promise.resolve(nread);
|
||||
}
|
||||
|
||||
readSync(p: Uint8Array): number | null {
|
||||
if (this.#offset >= this.#buf.length) {
|
||||
return null;
|
||||
}
|
||||
const nread = Math.min(p.length, 16_384, this.#buf.length - this.#offset);
|
||||
if (nread === 0) {
|
||||
return 0;
|
||||
}
|
||||
copy(this.#buf.subarray(this.#offset, this.#offset + nread), p);
|
||||
this.#offset += nread;
|
||||
return nread;
|
||||
}
|
||||
|
||||
seek(offset: number, whence: Deno.SeekMode): Promise<number> {
|
||||
assert(whence === Deno.SeekMode.Start);
|
||||
if (offset >= this.#buf.length) {
|
||||
return Promise.reject(
|
||||
new RangeError("Attempted to seek past end of buffer"),
|
||||
);
|
||||
}
|
||||
this.#offset = offset;
|
||||
return Promise.resolve(this.#offset);
|
||||
}
|
||||
|
||||
seekSync(offset: number, whence: Deno.SeekMode): number {
|
||||
assert(whence === Deno.SeekMode.Start);
|
||||
if (offset >= this.#buf.length) {
|
||||
throw new RangeError("Attempted to seek past end of buffer");
|
||||
}
|
||||
this.#offset = offset;
|
||||
return this.#offset;
|
||||
}
|
||||
}
|
||||
|
||||
Deno.test({
|
||||
name: "readRange",
|
||||
async fn() {
|
||||
init();
|
||||
assert(testBytes);
|
||||
const file = new MockFile(testBytes);
|
||||
const actual = await readRange(file, { start: 0, end: 9 });
|
||||
assertEquals(actual, testBytes.subarray(0, 10));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "readRange - invalid range",
|
||||
async fn() {
|
||||
init();
|
||||
assert(testBytes);
|
||||
const file = new MockFile(testBytes);
|
||||
await assertRejects(
|
||||
async () => {
|
||||
await readRange(file, { start: 100, end: 0 });
|
||||
},
|
||||
Error,
|
||||
"Byte range start cannot be larger than end",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "readRange - read past EOF",
|
||||
async fn() {
|
||||
init();
|
||||
assert(testBytes);
|
||||
const file = new MockFile(testBytes);
|
||||
await assertRejects(
|
||||
async () => {
|
||||
await readRange(file, { start: 99, end: 100 });
|
||||
},
|
||||
Error,
|
||||
"Unexpected EOF reach while reading a range",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "readRangeSync",
|
||||
fn() {
|
||||
init();
|
||||
assert(testBytes);
|
||||
const file = new MockFile(testBytes);
|
||||
const actual = readRangeSync(file, { start: 0, end: 9 });
|
||||
assertEquals(actual, testBytes.subarray(0, 10));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "readRangeSync - invalid range",
|
||||
fn() {
|
||||
init();
|
||||
assert(testBytes);
|
||||
const file = new MockFile(testBytes);
|
||||
assertThrows(
|
||||
() => {
|
||||
readRangeSync(file, { start: 100, end: 0 });
|
||||
},
|
||||
Error,
|
||||
"Byte range start cannot be larger than end",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "readRangeSync - read past EOF",
|
||||
fn() {
|
||||
init();
|
||||
assert(testBytes);
|
||||
const file = new MockFile(testBytes);
|
||||
assertThrows(
|
||||
() => {
|
||||
readRangeSync(file, { start: 99, end: 100 });
|
||||
},
|
||||
Error,
|
||||
"Unexpected EOF reach while reading a range",
|
||||
);
|
||||
},
|
||||
});
|
Loading…
Reference in New Issue
Block a user