Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing Buffer APIs; update CI: node and actions versions #55

Merged
merged 7 commits into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ Breaking changes:
```

New features:
- Added the following APIs (#55 by @JordanMartinez)

- `Buffer.alloc`, `Buffer.allocUnsafe`, `Buffer.allocUnsafeSlow`
- `Buffer.poolSize`, `Buffer.setPoolSize`
- `buffer.swap16`, `buffer.swap32`, `buffer.swap64`
- `buffer.compare`: https://nodejs.org/docs/latest-v18.x/api/buffer.html#bufcomparetarget-targetstart-targetend-sourcestart-sourceend
- `buffer.toString(encoding, start, end)`: https://nodejs.org/docs/latest-v18.x/api/buffer.html#buftostringencoding-start-end
- `buffer.transcode(buf, from, to)`
- constants:
- `INSPECT_MAX_BYTES`: https://nodejs.org/docs/latest-v18.x/api/buffer.html#bufferinspect_max_bytes
- `MAX_LENGTH`: https://nodejs.org/docs/latest-v18.x/api/buffer.html#bufferconstantsmax_length
- `MAX_STRING_LENGTH`: https://nodejs.org/docs/latest-v18.x/api/buffer.html#bufferconstantsmax_string_length


Bugfixes:

Expand Down
16 changes: 15 additions & 1 deletion src/Node/Buffer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { Buffer } from "node:buffer";
import { Buffer, transcode } from "node:buffer";

export const allocUnsafeImpl = (size) => Buffer.allocUnsafe(size);
export const allocUnsafeSlowImpl = (size) => Buffer.allocUnsafeSlow(size);

export const freezeImpl = (a) => Buffer.from(a);
export const thawImpl = (a) => Buffer.from(a);
Expand All @@ -17,3 +20,14 @@ export const copyImpl = (srcStart, srcEnd, src, targStart, targ) =>

export const fillImpl = (octet, start, end, buf) =>
buf.fill(octet, start, end);

export const poolSize = () => Buffer.poolSize;

export const setPoolSizeImpl = (size) => {
Buffer.poolSize = size;
};

export const swap16Impl = (buf) => buf.swap16();
export const swap32Impl = (buf) => buf.swap32();
export const swap64Impl = (buf) => buf.swap64();
export const transcodeImpl = (buf, from, to) => transcode(buf, from, to);
69 changes: 68 additions & 1 deletion src/Node/Buffer.purs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ module Node.Buffer
( Buffer
, module TypesExports
, create
, alloc
, allocUnsafe
, allocUnsafeSlow
, compareParts
, freeze
, unsafeFreeze
, thaw
Expand All @@ -14,6 +18,7 @@ module Node.Buffer
, read
, readString
, toString
, toString'
, write
, writeString
, toArray
Expand All @@ -25,6 +30,12 @@ module Node.Buffer
, concat'
, copy
, fill
, poolSize
, setPoolSize
, swap16
, swap32
, swap64
, transcode
) where

import Prelude
Expand Down Expand Up @@ -81,8 +92,27 @@ usingFromImmutable f buf = f <$> unsafeFreeze buf
usingToImmutable :: forall a. (a -> ImmutableBuffer) -> a -> Effect Buffer
usingToImmutable f x = unsafeThaw $ f x

-- | Creates a new buffer of the specified size. Alias to `alloc`.
create :: Int -> Effect Buffer
create = usingToImmutable Immutable.create
create = alloc

-- | Creates a new buffer of the specified size.
alloc :: Int -> Effect Buffer
alloc = usingToImmutable Immutable.alloc

-- | Creates a new buffer of the specified size. Unsafe because it reuses memory from a pool
-- | and may contain sensitive data. See the Node docs.
JordanMartinez marked this conversation as resolved.
Show resolved Hide resolved
allocUnsafe :: Int -> Effect Buffer
allocUnsafe s = runEffectFn1 allocUnsafeImpl s

foreign import allocUnsafeImpl :: EffectFn1 (Int) (Buffer)

-- | Creates a new buffer of the specified size. Unsafe because it reuses memory from a pool
-- | and may contain sensitive data. See the Node docs.
allocUnsafeSlow :: Int -> Effect Buffer
allocUnsafeSlow s = runEffectFn1 allocUnsafeSlowImpl s

foreign import allocUnsafeSlowImpl :: EffectFn1 (Int) (Buffer)

freeze :: Buffer -> Effect ImmutableBuffer
freeze = runEffectFn1 freezeImpl
Expand All @@ -106,6 +136,12 @@ fromArrayBuffer = usingToImmutable Immutable.fromArrayBuffer
toArrayBuffer :: Buffer -> Effect ArrayBuffer
toArrayBuffer = usingFromImmutable Immutable.toArrayBuffer

compareParts :: Buffer -> Buffer -> Offset -> Offset -> Offset -> Offset -> Effect Ordering
compareParts src target targetSrc targetEnd srcStart srcEnd = do
src' <- unsafeFreeze src
target' <- unsafeFreeze target
Immutable.compareParts src' target' targetSrc targetEnd srcStart srcEnd

read :: BufferValueType -> Offset -> Buffer -> Effect Number
read t o = usingFromImmutable $ Immutable.read t o

Expand All @@ -115,6 +151,9 @@ readString enc o o' = usingFromImmutable $ Immutable.readString enc o o'
toString :: Encoding -> Buffer -> Effect String
toString enc = usingFromImmutable $ Immutable.toString enc

toString' :: Encoding -> Offset -> Offset -> Buffer -> Effect String
toString' enc start end = usingFromImmutable $ Immutable.toString' enc start end

write :: BufferValueType -> Number -> Offset -> Buffer -> Effect Unit
write ty value offset buf = runEffectFn4 writeInternal (show ty) value offset buf

Expand Down Expand Up @@ -160,3 +199,31 @@ fill octet start end buf = do
runEffectFn4 fillImpl octet start end buf

foreign import fillImpl :: EffectFn4 Octet Offset Offset Buffer Unit

-- | The size (in bytes) of pre-allocated internal Buffer instances used for pooling. This value may be modified.
foreign import poolSize :: Effect (Int)

setPoolSize :: Int -> Effect Unit
setPoolSize sizeInBytes = runEffectFn1 setPoolSizeImpl sizeInBytes

foreign import setPoolSizeImpl :: EffectFn1 (Int) (Unit)

swap16 :: Buffer -> Effect Buffer
swap16 b = runEffectFn1 swap16Impl b

foreign import swap16Impl :: EffectFn1 (Buffer) (Buffer)

swap32 :: Buffer -> Effect Buffer
swap32 b = runEffectFn1 swap32Impl b

foreign import swap32Impl :: EffectFn1 (Buffer) (Buffer)

swap64 :: Buffer -> Effect Buffer
swap64 b = runEffectFn1 swap64Impl b

foreign import swap64Impl :: EffectFn1 (Buffer) (Buffer)

transcode :: Buffer -> Encoding -> Encoding -> Effect Buffer
transcode buf from to = runEffectFn3 transcodeImpl buf (encodingToNode from) (encodingToNode to)

foreign import transcodeImpl :: EffectFn3 (Buffer) (String) (String) (Buffer)
5 changes: 5 additions & 0 deletions src/Node/Buffer/Constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import buffer from "node:buffer";

export const inspectMaxBytes = () => buffer.INSPECT_MAX_LENGTH;
export const maxLength = buffer.constants.MAX_LENGTH;
export const maxStringLength = buffer.constants.MAX_STRING_LENGTH;
9 changes: 9 additions & 0 deletions src/Node/Buffer/Constants.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Node.Buffer.Constants where

import Effect (Effect)

foreign import inspectMaxBytes :: Effect Int

foreign import maxLength :: Int

foreign import maxStringLength :: Int
7 changes: 6 additions & 1 deletion src/Node/Buffer/Immutable.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ export const eqImpl = (a, b) => a.equals(b);

export const compareImpl = (a, b) => a.compare(b);

export const create = (size) => Buffer.alloc(size);
export const comparePartsImpl = (src, target, targetStart, targetEnd, sourceStart, sourceEnd) =>
src.compare(target, targetStart, targetEnd, sourceStart, sourceEnd);

export const alloc = (size) => Buffer.alloc(size);

export const fromArray = (octets) => Buffer.from(octets);

Expand All @@ -33,6 +36,8 @@ export const getAtOffsetImpl = (offset, buff) => buff[offset];

export const toStringImpl = (enc, buff) => buff.toString(enc);

export const toStringSubImpl = (enc, start, end, buff) => buff.toString(enc, start, end);

export const sliceImpl = (start, end, buff) => buff.slice(start, end);

export const concat = (buffs) => Buffer.concat(buffs);
Expand Down
31 changes: 27 additions & 4 deletions src/Node/Buffer/Immutable.purs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
-- | Immutable buffers and associated operations.
module Node.Buffer.Immutable
( ImmutableBuffer
, compareParts
, create
, alloc
, fromArray
, fromString
, fromArrayBuffer
, read
, readString
, toString
, toString'
, toArray
, toArrayBuffer
, getAtOffset
Expand All @@ -23,8 +26,11 @@ import Data.ArrayBuffer.Types (ArrayBuffer)
import Data.Function.Uncurried (Fn2, Fn3, Fn4, runFn2, runFn3, runFn4)
import Data.Maybe (Maybe)
import Data.Nullable (Nullable, toMaybe)
import Effect (Effect)
import Effect.Uncurried (EffectFn6, runEffectFn6)
import Node.Buffer.Types (BufferValueType, Octet, Offset)
import Node.Encoding (Encoding, encodingToNode)
import Partial.Unsafe (unsafeCrashWith)

-- | An immutable buffer that exists independently of any memory region or effect.
foreign import data ImmutableBuffer :: Type
Expand All @@ -48,23 +54,35 @@ instance ordBuffer :: Ord ImmutableBuffer where

foreign import compareImpl :: Fn2 ImmutableBuffer ImmutableBuffer Int

-- | Creates a new buffer of the specified size. Alias for `alloc`.
create :: Int -> ImmutableBuffer
create = alloc

-- | Creates a new buffer of the specified size.
foreign import create :: Int -> ImmutableBuffer
foreign import alloc :: Int -> ImmutableBuffer

-- | Creates a new buffer from an array of octets, sized to match the array.
foreign import fromArray :: Array Octet -> ImmutableBuffer

-- | Creates a buffer view from a JS ArrayByffer without copying data.
--
-- Requires Node >= v5.10.0
foreign import fromArrayBuffer :: ArrayBuffer -> ImmutableBuffer

-- | Creates a new buffer from a string with the specified encoding, sized to match the string.
fromString :: String -> Encoding -> ImmutableBuffer
fromString str = runFn2 fromStringImpl str <<< encodingToNode
fromString str enc = runFn2 fromStringImpl str $ encodingToNode enc

foreign import fromStringImpl :: Fn2 String String ImmutableBuffer

compareParts :: ImmutableBuffer -> ImmutableBuffer -> Offset -> Offset -> Offset -> Offset -> Effect Ordering
compareParts src target targetStart targetEnd sourceStart sourceEnd =
runEffectFn6 comparePartsImpl src target targetStart targetEnd sourceStart sourceEnd <#> case _ of
-1 -> LT
0 -> EQ
1 -> GT
x -> unsafeCrashWith $ "Impossible: Invalid value: " <> show x

foreign import comparePartsImpl :: EffectFn6 ImmutableBuffer ImmutableBuffer Int Int Int Int Int

-- | Reads a numeric value from a buffer at the specified offset.
read :: BufferValueType -> Offset -> ImmutableBuffer -> Number
read ty off buf = runFn3 readImpl (show ty) off buf
Expand All @@ -83,6 +101,11 @@ toString enc buf = runFn2 toStringImpl (encodingToNode enc) buf

foreign import toStringImpl :: Fn2 String ImmutableBuffer String

toString' :: Encoding -> Offset -> Offset -> ImmutableBuffer -> String
toString' enc start end buf = runFn4 toStringSubImpl enc start end buf

foreign import toStringSubImpl :: Fn4 Encoding Offset Offset ImmutableBuffer String

-- | Creates an array of octets from a buffer's contents.
foreign import toArray :: ImmutableBuffer -> Array Octet

Expand Down
Loading