Skip to content

Commit

Permalink
feat: Add Envelope (#195)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikuroXina committed May 6, 2024
1 parent de8abbd commit 8a410bc
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 0 deletions.
1 change: 1 addition & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * as Coyoneda from "./src/coyoneda.ts";
export * as Curry from "./src/curry.ts";
export * as Dom from "./src/dom.ts";
export * as Dual from "./src/dual.ts";
export * as Envelope from "./src/envelope.ts";
export * as Ether from "./src/ether.ts";
export * as Exists from "./src/exists.ts";
export * as Free from "./src/free.ts";
Expand Down
70 changes: 70 additions & 0 deletions src/envelope.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { doT } from "./cat.ts";
import {
type Code,
type Decoder,
decUtf8,
type Encoder,
encUtf8,
failDecoder,
monadForCodeM,
monadForDecoder,
} from "./serial.ts";

/**
* A envelope object to transport data into another machine.
*/
export type Envelope<T> = Readonly<{
/**
* The namespace URL of your data. It can be an URL to the scheme of your data format.
*/
namespace: string;
/**
* The packed payload object.
*/
payload: T;
}>;

/**
* Packs a payload object into a new envelope.
*
* @param namespace - The namespace URL of your data. It can be an URL to the scheme of your data format.
* @param payload - A payload object to be packed.
* @returns The new envelope with `payload`.
*/
export const pack = (namespace: string) => <T>(payload: T): Envelope<T> => ({
namespace,
payload,
});

/**
* Creates an `Encoder` for `Envelope<T>` from a `Encoder<T>`.
*
* @param encodeT - A payload encoder.
* @returns The new encoder for `Envelope<T>`.
*/
export const encode =
<T>(encodeT: Encoder<T>): Encoder<Envelope<T>> =>
(env: Envelope<T>): Code =>
doT(monadForCodeM)
.run(encUtf8(env.namespace))
.finishM(() => encodeT(env.payload));
/**
* Creates a `Decoder` for `Envelope<T>` from the namespace and a `Decoder<T>`. It fails when found a namespace that didn't equal to `namespace`.
*
* @param namespace - The expected namespace of data.
* @param decodeT - A payload decoder.
* @returns The new decoder for `Envelope<T>`.
*/
export const decodeFor =
(namespace: string) => <T>(decodeT: Decoder<T>): Decoder<Envelope<T>> =>
doT(monadForDecoder)
.addM("actualNamespace", decUtf8())
.when(
({ actualNamespace }) => actualNamespace !== namespace,
({ actualNamespace }) =>
failDecoder(
`expected namespace '${namespace}' but found '${actualNamespace}'`,
),
)
.addM("payload", decodeT)
.finish(({ payload }) => pack(namespace)(payload));

0 comments on commit 8a410bc

Please sign in to comment.