Skip to content

Commit

Permalink
feat: worker and delay. (#88)
Browse files Browse the repository at this point in the history
* change year.

* update deps.

* feat: worker-task

* fix test code.

* fix test code.

* worker type.

* remove unstable permission.

* add jsdoc.

* transfer typedarray.

* revoke url each time.

* dispose method.

* feat: delay

* wording.

* feat: primitive type convert

* change file name.

* add jsdoc.

* fix primitive.

* feat primitive convert and remove env.

* fix log deprecated.
  • Loading branch information
dojyorin authored Jan 22, 2024
1 parent 91f3647 commit 6de3cfc
Show file tree
Hide file tree
Showing 16 changed files with 295 additions and 70 deletions.
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2023 Kazuki Ota
Copyright (c) 2024 Kazuki Ota

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
6 changes: 3 additions & 3 deletions deps.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export {assertEquals} from "https://deno.land/std@0.210.0/assert/mod.ts";
export {dirname, fromFileUrl} from "https://deno.land/std@0.210.0/path/mod.ts";
export {exists} from "https://deno.land/std@0.210.0/fs/mod.ts";
export {assertEquals} from "https://deno.land/std@0.212.0/assert/mod.ts";
export {dirname, fromFileUrl} from "https://deno.land/std@0.212.0/path/mod.ts";
export {exists} from "https://deno.land/std@0.212.0/fs/mod.ts";
6 changes: 3 additions & 3 deletions deps.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export {dirname, fromFileUrl} from "https://deno.land/std@0.210.0/path/mod.ts";
export {Logger, handlers} from "https://deno.land/std@0.210.0/log/mod.ts";
export {format} from "https://deno.land/std@0.210.0/datetime/mod.ts";
export {dirname, fromFileUrl} from "https://deno.land/std@0.212.0/path/mod.ts";
export {Logger, ConsoleHandler, FileHandler} from "https://deno.land/std@0.212.0/log/mod.ts";
export {format} from "https://deno.land/std@0.212.0/datetime/mod.ts";
5 changes: 3 additions & 2 deletions mod.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ import "./test/byte.test.ts";
import "./test/crypto.test.ts";
import "./test/deep.test.ts";
import "./test/deflate.test.ts";
import "./test/env.deno.test.ts";
import "./test/fetch.test.ts";
import "./test/import.test.ts";
import "./test/json.deno.test.ts";
import "./test/log.deno.test.ts";
import "./test/minipack.test.ts";
import "./test/path.deno.test.ts";
import "./test/platform.deno.test.ts";
import "./test/primitive.test.ts";
import "./test/process.deno.test.ts";
import "./test/stream.test.ts";
import "./test/text.test.ts";
import "./test/time.test.ts";
import "./test/time.test.ts";
import "./test/worker.test.ts";
3 changes: 2 additions & 1 deletion mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ export * from "./src/deflate.ts";
export * from "./src/fetch.ts";
export * from "./src/import.ts";
export * from "./src/minipack.ts";
export * from "./src/primitive.ts";
export * from "./src/stream.ts";
export * from "./src/text.ts";
export * from "./src/time.ts";
export * from "./src/worker.ts";

export * from "./src/env.deno.ts";
export * from "./src/json.deno.ts";
export * from "./src/log.deno.ts";
export * from "./src/path.deno.ts";
Expand Down
4 changes: 3 additions & 1 deletion mod.universal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export * from "./src/deflate.ts";
export * from "./src/fetch.ts";
export * from "./src/import.ts";
export * from "./src/minipack.ts";
export * from "./src/primitive.ts";
export * from "./src/stream.ts";
export * from "./src/text.ts";
export * from "./src/time.ts";
export * from "./src/time.ts";
export * from "./src/worker.ts";
35 changes: 0 additions & 35 deletions src/env.deno.ts

This file was deleted.

6 changes: 3 additions & 3 deletions src/log.deno.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Logger, handlers, format} from "../deps.ts";
import {Logger, ConsoleHandler, FileHandler, format} from "../deps.ts";
import {mainPath} from "./path.deno.ts";

function logRecord(date:Date, level:string, message:string){
Expand All @@ -19,7 +19,7 @@ export function logEntry(name?:string):Logger{

const log = new Logger("operation", level, {
handlers: [
new handlers.ConsoleHandler(level, {
new ConsoleHandler(level, {
formatter({datetime, levelName, msg}){
return logRecord(datetime, levelName, msg);
}
Expand All @@ -29,7 +29,7 @@ export function logEntry(name?:string):Logger{

if(name){
log.handlers.push(...[
new handlers.FileHandler(level, {
new FileHandler(level, {
filename: `${mainPath()}/${name}.log`,
formatter({datetime, levelName, msg}){
return logRecord(datetime, levelName, msg);
Expand Down
116 changes: 116 additions & 0 deletions src/primitive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
* Infer data type from literal type.
*/
export type WidenLiteral<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T;

/**
* Something that might be string.
*/
export type MaybeString = string | null | undefined;

/**
* Whether to allow `undefined`.
*/
export type TypeStrict<T extends unknown, U extends boolean> = U extends true ? T : T | undefined;

/**
* Map of primitive types and string that specify them.
*/
export interface PrimitiveMap{
"string": string;
"number": number;
"boolean": boolean;
}

function undef(strict?:boolean){
if(strict){
throw new Error();
}

return undefined;
}

/**
* Convert from dirty text to specified type.
* Enabling `strict` flag will throw exception if parsing is not possible.
* @example
* ```ts
* const value = primitiveParse("123", "number", true);
* ```
*/
export function primitiveParse<T extends keyof PrimitiveMap, U extends boolean>(text:MaybeString, type:T, strict?:U):TypeStrict<PrimitiveMap[T], U>{
switch(type){
case "string": {
const v = String(text);

if(text === undefined || text === null){
return <TypeStrict<PrimitiveMap[T], U>>undef(strict);
}

return <TypeStrict<PrimitiveMap[T], U>>v;
}

case "number": {
const v = Number(text);

if(text === undefined || text === null || isNaN(v)){
return <TypeStrict<PrimitiveMap[T], U>>undef(strict);
}

return <TypeStrict<PrimitiveMap[T], U>>v;
}

case "boolean": {
switch(text){
case "true": return <TypeStrict<PrimitiveMap[T], U>>true;
case "false": return <TypeStrict<PrimitiveMap[T], U>>false;
default: return <TypeStrict<PrimitiveMap[T], U>>undef(strict);
}
}

default: throw new Error();
}
}

/**
* Convert from dirty text to specified type.
* If cannot be parsed, use default (`def`) value.
* Convert to same type as default value.
* @example
* ```ts
* const value = primitiveParseX("123", 0);
* ```
*/
export function primitiveParseX<T extends string | number | boolean>(text:MaybeString, def:T):WidenLiteral<T>{
switch(typeof def){
case "string": {
const v = String(text);

if(text === undefined || text === null){
return <WidenLiteral<T>>def;
}

return <WidenLiteral<T>>v;
}

case "number": {
const v = Number(text);

if(text === undefined || text === null || isNaN(v)){
return <WidenLiteral<T>>def;
}

return <WidenLiteral<T>>v;
}

case "boolean": {
switch(text){
case "true": return <WidenLiteral<T>>true;
case "false": return <WidenLiteral<T>>false;
default: return <WidenLiteral<T>>def;
}
}

default: throw new Error();
}
}
11 changes: 11 additions & 0 deletions src/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,15 @@ export function utParse(ds:string):number{
const [y, m, d, h, mi, s] = ds.split(/[/ :TZ_.-]/i).map(v => Number(v));

return utEncode(new Date(y, (m ?? 1) - 1, d ?? 1, h ?? 0, mi ?? 0, s ?? 0));
}

/**
* Wait for specified time.
* @example
* ```ts
* await delay(1000);
* ```
*/
export async function delay(ms:number):Promise<void>{
await new Promise<void>(done => setTimeout(done, ms));
}
84 changes: 84 additions & 0 deletions src/worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* TypedArray also automatically unwrap to `ArrayBuffer`.
*/
export type TaskTransfer = Transferable | ArrayBufferView;

/**
* Content of processing run by worker thread.
*/
export type TaskAction<T extends unknown, K extends unknown> = (message:T) => TaskMessage<K> | Promise<TaskMessage<K>>;

/**
* Run registered `TaskAction` in worker thread.
*/
export type TaskContext<T extends unknown, K extends unknown> = (message:T, transfers?:TaskTransfer[]) => Promise<K>;

/**
* Communication content between main thread and worker thread.
*/
export interface TaskMessage<T extends unknown>{
message: T;
transfers?: TaskTransfer[];
}

/**
* Register `TaskAction` and return reusable task execution context.
* `Worker` instance is created and destroyed each time they run `TaskContext`.
* `import` can only use "syntax", not "declaration".
* @example
* ```ts
* const task = createTask<number, number>(async(data)=>{
* const {delay} = await import("https://deno.land/std/async/mod.ts");
* await delay(1000);
* return {
* message: data * 2
* };
* });
* const result1 = await task(1);
* const result2 = await task(2);
* ```
*/
export function createTask<T extends unknown, K extends unknown>(task:TaskAction<T, K>):TaskContext<T, K>{
const script = task.toString();
const regist = /*js*/`
globalThis.onmessage = async({data})=>{
const {message, transfers} = await(${script})(data);
globalThis.postMessage(message, {
transfer: transfers?.map(v => "buffer" in v ? v.buffer : v)
});
};
`;

return (message, transfers)=>{
return new Promise<K>((res, rej)=>{
const url = URL.createObjectURL(new Blob([regist]));
const worker = new Worker(url, {
type: "module"
});

function dispose(){
worker.terminate();
URL.revokeObjectURL(url);
}

worker.onmessage = ({data})=>{
res(data);
dispose();
};

worker.onerror = (e)=>{
rej(e);
dispose();
};

worker.onmessageerror = (e)=>{
rej(e);
dispose();
};

worker.postMessage(message, {
transfer: transfers?.map(v => "buffer" in v ? v.buffer : v)
});
});
};
}
19 changes: 0 additions & 19 deletions test/env.deno.test.ts

This file was deleted.

Loading

0 comments on commit 6de3cfc

Please sign in to comment.