From 13b3c235e68e9a63123080cc9e3da6cca54d7b5f Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 2 Feb 2024 15:43:46 +1300 Subject: [PATCH] fix for encoding of Transferable schemas --- .changeset/ten-pandas-brake.md | 5 +++ packages/platform/src/Transferable.ts | 44 ++++++++++++++------- packages/platform/test/Transferable.test.ts | 32 +++++++++++++-- 3 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 .changeset/ten-pandas-brake.md diff --git a/.changeset/ten-pandas-brake.md b/.changeset/ten-pandas-brake.md new file mode 100644 index 0000000000..b9427e29a6 --- /dev/null +++ b/.changeset/ten-pandas-brake.md @@ -0,0 +1,5 @@ +--- +"@effect/platform": minor +--- + +fix for encoding of Transferable schemas diff --git a/packages/platform/src/Transferable.ts b/packages/platform/src/Transferable.ts index 92b94f0000..ed3ba7a138 100644 --- a/packages/platform/src/Transferable.ts +++ b/packages/platform/src/Transferable.ts @@ -37,6 +37,14 @@ export const get = (u: unknown): ReadonlyArray => { return [] } +/** + * @since 1.0.0 + * @category schema + */ +export interface TransferableSchema extends Schema.Schema { + (_: A): A & Transferable +} + /** * @since 1.0.0 * @category schema @@ -44,11 +52,11 @@ export const get = (u: unknown): ReadonlyArray => { export const schema: { ( f: (_: A) => ReadonlyArray - ): (self: Schema.Schema) => Schema.Schema + ): (self: Schema.Schema) => TransferableSchema ( self: Schema.Schema, f: (_: A) => ReadonlyArray - ): Schema.Schema + ): TransferableSchema } = dual(2, ( self: Schema.Schema, f: (_: A) => ReadonlyArray @@ -56,38 +64,44 @@ export const schema: { const fn: Transferable[typeof symbol] = function(this: A) { return f(this) } - return Schema.transform( + const schema = Schema.transform( self, schemaFromSelf(Schema.to(self)), (input) => addProxy(input, fn), identity ) + function make(self: A): A & Transferable { + return addProxy(self, fn) + } + Object.setPrototypeOf(make, Object.getPrototypeOf(schema)) + make.ast = schema.ast + return make }) -const schemaParse = - (parse: ParseResult.DecodeUnknown): ParseResult.DeclarationDecodeUnknown => - (u, options, ast) => { - if (!isTransferable(u)) { - return ParseResult.fail(ParseResult.type(ast, u)) - } - const f = u[symbol] - return ParseResult.map(parse(u, options), (a): A => addProxy(a, f)) +const schemaParse = ( + parse: ParseResult.DecodeUnknown +): ParseResult.DeclarationDecodeUnknown => +(u, options, ast) => { + if (!isTransferable(u)) { + return ParseResult.fail(ParseResult.type(ast, u)) } + const f = u[symbol] + return ParseResult.map(parse(u, options), (a) => addProxy(a, f)) +} /** * @since 1.0.0 * @category schema */ -export const schemaFromSelf = ( +export const schemaFromSelf = ( item: Schema.Schema -): Schema.Schema => { - return Schema.declare( +): Schema.Schema => + Schema.declare( [item], (item) => schemaParse(ParseResult.decodeUnknown(item)), (item) => schemaParse(ParseResult.encodeUnknown(item)), { identifier: "Transferable" } ) -} const addProxy = (self: A, f: Transferable[typeof symbol]): A & Transferable => { return new Proxy(self, { diff --git a/packages/platform/test/Transferable.test.ts b/packages/platform/test/Transferable.test.ts index 02bd37c769..1172db07b9 100644 --- a/packages/platform/test/Transferable.test.ts +++ b/packages/platform/test/Transferable.test.ts @@ -2,6 +2,11 @@ import * as Transferable from "@effect/platform/Transferable" import { Schema } from "@effect/schema" import { assert, describe, test } from "vitest" +const TransferableUint8Array = Transferable.schema( + Schema.Uint8ArrayFromSelf, + (_) => [_.buffer] +) + describe("Transferable", () => { test("calls symbol", () => { class Test implements Transferable.Transferable { @@ -28,11 +33,32 @@ describe("Transferable", () => { test("schema Uint8Array", () => { const array = new Uint8Array([1, 2, 3]) + const data = Schema.decodeSync(TransferableUint8Array)(array) + assert.deepEqual(Transferable.get(data), [array.buffer]) + }) + + test("schema encode", () => { const schema = Transferable.schema( - Schema.Uint8ArrayFromSelf, - (_) => [_.buffer] + Schema.struct({ + data: Schema.Uint8ArrayFromSelf + }), + (_) => [_.data.buffer] ) - const data = Schema.decodeSync(schema)(array) + const array = new Uint8Array([1, 2, 3]) + const data = schema({ + data: array + }) + assert.deepEqual(Transferable.get(data), [array.buffer]) + + const encoded = Schema.encodeSync(schema)(data) + assert.deepEqual(encoded, { + data: array + }) + }) + + test("schema encode Uint8Array", () => { + const array = new Uint8Array([1, 2, 3]) + const data = TransferableUint8Array(array) assert.deepEqual(Transferable.get(data), [array.buffer]) }) })