You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Firstly, great work on this lib and fp-ts in general. Definitely has changed the way I think about writing software big time. Secondly, why I'm here, hoping you can help me use parser-ts more easily/efficiently for binary messages in a Node environment.
Any help or advice greatly appreciated!
Current Behavior
Currently it's not easy to use a Stream<A> with a buffer of the Node Buffer type. I'm able to make it work by casting to an Array<number> on construction, which works fine since the lib code is only doing lookups, length checks and slices I believe, all of which are supported by Buffer and/or its parent interface Uint8Array.
Desired Behavior
It'd be nice to support the Buffer type also. It'd also be nice to have getMany/ getManyAndNext functions for extracting a slice of a buffer. For example in the wire protocol I'm looking at (PostgreSQL) some messages have 32 bit big endian length prefixes which indicate the length of the buffer following that pertain to that message.
Suggested Solution
I've been able to get some stuff working with a bit of casting here and there. Here's a test program to demonstrate:
import { pipe } from 'fp-ts/lib/function';
import * as O from 'fp-ts/lib/Option';
import * as E from 'fp-ts/lib/Either';
import * as P from 'parser-ts/Parser';
import * as PR from 'parser-ts/ParseResult';
import * as S from 'parser-ts/Stream';
type Byte = number;
const stream: (buf: Buffer, cursor?: number) => S.Stream<Byte> = (
buf,
cursor
) => S.stream(buf as unknown as Array<number>, cursor); // Buffer behaves enough like an Array for use by parser-ts - that is, supports: slice, at/[], length
function buffer(i: Buffer): P.Parser<Byte, Buffer>;
function buffer(i: string, enc?: BufferEncoding): P.Parser<Byte, Buffer>;
function buffer(
i: string | Buffer,
enc?: BufferEncoding
): P.Parser<Byte, Buffer> {
let buf: Buffer;
if (typeof i === 'string') {
buf = Buffer.from(i, enc);
} else {
buf = i;
}
return P.expected(
P.ChainRec.chainRec<Byte, Buffer, Buffer>(buf, (acc) =>
pipe(
O.fromNullable(acc.at(0)),
O.fold(
() => P.of(E.right(buf)),
(c) =>
pipe(
P.sat((b: Byte) => b === c),
P.chain(() => P.of(E.left(acc.slice(1))))
)
)
)
),
JSON.stringify(buf)
);
}
const getManyAndNext: <A>(
i: S.Stream<A>,
count: number
) => O.Option<{
value: A[];
next: S.Stream<A>;
}> = (i, count) => {
const endIndex = count + i.cursor;
if (endIndex <= i.buffer.length) {
return O.some({
value: i.buffer.slice(i.cursor, endIndex), // our buffer using Buffer actually outputs a Buffer here, not an Array<number>
next: S.stream(i.buffer, endIndex)
});
}
return O.none;
};
const items: <A>(count: number) => P.Parser<A, Array<A>> =
(count: number) => (i) =>
pipe(
getManyAndNext(i, count),
O.fold(
() => PR.error(i),
({ value, next }) => PR.success(value, next, i)
)
);
const uint32BE = pipe(
items<number>(4),
P.map((buf) => Buffer.from(buf).readUInt32BE()) // not ideal - creating a buf here is not necessary
// P.map((buf) => (buf as unknown as Buffer).readUInt32BE()) // this is more efficient/ works too but relies on casting
);
const bufParser = pipe(
buffer('x'),
P.chain(() => uint32BE),
P.chain((n) => items(n))
);
const buf = Buffer.allocUnsafe(11);
buf.write('x');
buf.writeUint32BE(5, 1);
buf.writeUint8(1, 5);
buf.writeUint8(2, 6);
buf.writeUint8(3, 7);
buf.writeUint8(4, 8);
buf.writeUint8(5, 9);
buf.writeUint8(6, 10);
console.log(bufParser(stream(buf)));
// Output:
// {
// _tag: 'Right',
// right: {
// value: <Buffer 01 02 03 04 05>,
// next: { buffer: <Buffer 78 00 00 00 05 01 02 03 04 05 06>, cursor: 10 },
// start: { buffer: <Buffer 78 00 00 00 05 01 02 03 04 05 06>, cursor: 0 }
// }
// }
Who does this impact? Who is this for?
This is for being able to create a parser that deals easily and efficiently with binary content.
Software
Version(s)
fp-ts
2.11.9
parser-ts
0.6.16
TypeScript
4.5.2
The text was updated successfully, but these errors were encountered:
🚀 Feature request
Firstly, great work on this lib and
fp-ts
in general. Definitely has changed the way I think about writing software big time. Secondly, why I'm here, hoping you can help me useparser-ts
more easily/efficiently for binary messages in a Node environment.Any help or advice greatly appreciated!
Current Behavior
Currently it's not easy to use a
Stream<A>
with a buffer of the NodeBuffer
type. I'm able to make it work by casting to anArray<number>
on construction, which works fine since the lib code is only doing lookups, length checks and slices I believe, all of which are supported byBuffer
and/or its parent interfaceUint8Array
.Desired Behavior
It'd be nice to support the
Buffer
type also. It'd also be nice to havegetMany
/getManyAndNext
functions for extracting a slice of a buffer. For example in the wire protocol I'm looking at (PostgreSQL) some messages have 32 bit big endian length prefixes which indicate the length of the buffer following that pertain to that message.Suggested Solution
I've been able to get some stuff working with a bit of casting here and there. Here's a test program to demonstrate:
Who does this impact? Who is this for?
This is for being able to create a parser that deals easily and efficiently with binary content.
The text was updated successfully, but these errors were encountered: