diff --git a/CHANGELOG.md b/CHANGELOG.md index bc79822..0c6026e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,43 @@ Notable changes to this project are documented in this file. The format is based ## [Unreleased] Breaking changes: +- Expose Buffer API using typeclass-less API witout removing typeclass API (#53 by @JordanMartinez) + + Previously, compiler would fail to infer the type of `Buffer.create 1` as `Effect Buffer` + because the Buffer API was exposed only via the multiparameter typeclass `MonadBuffer`. + Due to the functional dependency between the two parameters, the monadic type cannot be inferred + until the buffer type is known (either `Buffer` or `STBuffer`).: + ```purs + import Node.Buffer as Buffer + + -- Example 1 + main :: Effect Unit + main = do + x <- Buffer.create 1 -- compiler: is this `Int -> Effect Buffer` or `Int -> ST h (STBuffer h)? + pure unit + ``` + + The workaround was to add a type annotation, indicating the `x` is a `Buffer`: + ```purs + import Node.Buffer as Buffer + + -- Example 2 + main :: Effect Unit + main = do + x :: Buffer <- Buffer.create 1 -- compiler: Oh! It's `Int -> Effect Buffer` + pure unit + ``` + + This change does not break anyone's code if one was using a `create` (or another such typeclass member) + to get `Int -> Effect Buffer`. Rather, such users can now drop the `:: Buffer` annotation + (i.e. Example 1 above now compiles). + + If one was using `create` to get `forall m buf. MonadBuffer buf m => Int -> m buf`, + then one will need to update their imports: + ```diff + -import Node.Buffer (class MonadBuffer) + +import Node.Buffer.Class (class MonadBuffer) + ``` New features: diff --git a/src/Node/Buffer.purs b/src/Node/Buffer.purs index 612afd3..dcff4e0 100644 --- a/src/Node/Buffer.purs +++ b/src/Node/Buffer.purs @@ -2,39 +2,136 @@ module Node.Buffer ( Buffer , module TypesExports - , module Class + , create + , freeze + , unsafeFreeze + , thaw + , unsafeThaw + , fromArray + , fromString + , fromArrayBuffer + , toArrayBuffer + , read + , readString + , toString + , write + , writeString + , toArray + , getAtOffset + , setAtOffset + , slice + , size + , concat + , concat' + , copy + , fill ) where +import Prelude + +import Data.ArrayBuffer.Types (ArrayBuffer) +import Data.Maybe (Maybe) import Effect (Effect) import Node.Buffer.Class (class MutableBuffer) -import Node.Buffer.Class (class MutableBuffer, concat, concat', copy, create, fill, freeze, fromArray, fromArrayBuffer, fromString, getAtOffset, read, readString, setAtOffset, size, slice, thaw, toArray, toArrayBuffer, toString, unsafeFreeze, unsafeThaw, write, writeString) as Class +import Node.Buffer.Immutable (ImmutableBuffer) import Node.Buffer.Internal as Internal import Node.Buffer.Types (BufferValueType(..), Octet, Offset) as TypesExports +import Node.Buffer.Types (BufferValueType) +import Node.Encoding (Encoding) -- | A reference to a mutable buffer for use with `Effect` foreign import data Buffer :: Type instance mutableBufferEffect :: MutableBuffer Buffer Effect where - create = Internal.create - freeze = Internal.copyAll - unsafeFreeze = Internal.unsafeFreeze - thaw = Internal.copyAll - unsafeThaw = Internal.unsafeThaw - fromArray = Internal.fromArray - fromString = Internal.fromString - fromArrayBuffer = Internal.fromArrayBuffer - toArrayBuffer = Internal.toArrayBuffer - read = Internal.read - readString = Internal.readString - toString = Internal.toString - write = Internal.write - writeString = Internal.writeString - toArray = Internal.toArray - getAtOffset = Internal.getAtOffset - setAtOffset = Internal.setAtOffset - slice = Internal.slice - size = Internal.size - concat = Internal.concat - concat' = Internal.concat' - copy = Internal.copy - fill = Internal.fill + create = create + freeze = freeze + unsafeFreeze = unsafeFreeze + thaw = thaw + unsafeThaw = unsafeThaw + fromArray = fromArray + fromString = fromString + fromArrayBuffer = fromArrayBuffer + toArrayBuffer = toArrayBuffer + read = read + readString = readString + toString = toString + write = write + writeString = writeString + toArray = toArray + getAtOffset = getAtOffset + setAtOffset = setAtOffset + slice = slice + size = size + concat = concat + concat' = concat' + copy = copy + fill = fill + +create :: Int -> Effect Buffer +create = Internal.create + +freeze :: Buffer -> Effect ImmutableBuffer +freeze = Internal.copyAll + +unsafeFreeze :: Buffer -> Effect ImmutableBuffer +unsafeFreeze = Internal.unsafeFreeze + +thaw :: ImmutableBuffer -> Effect Buffer +thaw = Internal.copyAll + +unsafeThaw :: ImmutableBuffer -> Effect Buffer +unsafeThaw = Internal.unsafeThaw + +fromArray :: Array Int -> Effect Buffer +fromArray = Internal.fromArray + +fromString :: String -> Encoding -> Effect Buffer +fromString = Internal.fromString + +fromArrayBuffer :: ArrayBuffer -> Effect Buffer +fromArrayBuffer = Internal.fromArrayBuffer + +toArrayBuffer :: Buffer -> Effect ArrayBuffer +toArrayBuffer = Internal.toArrayBuffer + +read :: BufferValueType -> Int -> Buffer -> Effect Number +read = Internal.read + +readString :: Encoding -> Int -> Int -> Buffer -> Effect String +readString = Internal.readString + +toString :: Encoding -> Buffer -> Effect String +toString = Internal.toString + +write :: BufferValueType -> Number -> Int -> Buffer -> Effect Unit +write = Internal.write + +writeString :: Encoding -> Int -> Int -> String -> Buffer -> Effect Int +writeString = Internal.writeString + +toArray :: Buffer -> Effect (Array Int) +toArray = Internal.toArray + +getAtOffset :: Int -> Buffer -> Effect (Maybe Int) +getAtOffset = Internal.getAtOffset + +setAtOffset :: Int -> Int -> Buffer -> Effect Unit +setAtOffset = Internal.setAtOffset + +slice :: Int -> Int -> Buffer -> Buffer +slice = Internal.slice + +size :: Buffer -> Effect Int +size = Internal.size + +concat :: Array Buffer -> Effect Buffer +concat = Internal.concat + +concat' :: Array Buffer -> Int -> Effect Buffer +concat' = Internal.concat' + +copy :: Int -> Int -> Buffer -> Int -> Buffer -> Effect Int +copy = Internal.copy + +fill :: Int -> Int -> Int -> Buffer -> Effect Unit +fill = Internal.fill diff --git a/src/Node/Buffer/ST.purs b/src/Node/Buffer/ST.purs index fc84fec..40d3e2f 100644 --- a/src/Node/Buffer/ST.purs +++ b/src/Node/Buffer/ST.purs @@ -1,15 +1,42 @@ module Node.Buffer.ST ( STBuffer , run + , create + , freeze + , unsafeFreeze + , thaw + , unsafeThaw + , fromArray + , fromString + , fromArrayBuffer + , toArrayBuffer + , read + , readString + , toString + , write + , writeString + , toArray + , getAtOffset + , setAtOffset + , slice + , size + , concat + , concat' + , copy + , fill ) where import Prelude import Control.Monad.ST (ST, Region) import Control.Monad.ST as ST -import Node.Buffer.Class (class MutableBuffer, unsafeFreeze) +import Data.ArrayBuffer.Types (ArrayBuffer) +import Data.Maybe (Maybe) +import Node.Buffer (BufferValueType) +import Node.Buffer.Class (class MutableBuffer) import Node.Buffer.Immutable (ImmutableBuffer) import Node.Buffer.Internal as Internal +import Node.Encoding (Encoding) -- | A reference to a mutable buffer for use with `ST` -- | @@ -22,26 +49,95 @@ run :: (forall h. ST h (STBuffer h)) -> ImmutableBuffer run st = ST.run (st >>= unsafeFreeze) instance mutableBufferST :: MutableBuffer (STBuffer h) (ST h) where - create = Internal.create - freeze = Internal.copyAll - unsafeFreeze = Internal.unsafeFreeze - thaw = Internal.copyAll - unsafeThaw = Internal.unsafeThaw - fromArray = Internal.fromArray - fromString = Internal.fromString - fromArrayBuffer = Internal.fromArrayBuffer - toArrayBuffer = Internal.toArrayBuffer - read = Internal.read - readString = Internal.readString - toString = Internal.toString - write = Internal.write - writeString = Internal.writeString - toArray = Internal.toArray - getAtOffset = Internal.getAtOffset - setAtOffset = Internal.setAtOffset - slice = Internal.slice - size = Internal.size - concat = Internal.concat - concat' = Internal.concat' - copy = Internal.copy - fill = Internal.fill + create = create + freeze = freeze + unsafeFreeze = unsafeFreeze + thaw = thaw + unsafeThaw = unsafeThaw + fromArray = fromArray + fromString = fromString + fromArrayBuffer = fromArrayBuffer + toArrayBuffer = toArrayBuffer + read = read + readString = readString + toString = toString + write = write + writeString = writeString + toArray = toArray + getAtOffset = getAtOffset + setAtOffset = setAtOffset + slice = slice + size = size + concat = concat + concat' = concat' + copy = copy + fill = fill + +create :: forall h. Int -> ST h (STBuffer h) +create = Internal.create + +freeze :: forall h. STBuffer h -> ST h ImmutableBuffer +freeze = Internal.copyAll + +unsafeFreeze :: forall h. STBuffer h -> ST h ImmutableBuffer +unsafeFreeze = Internal.unsafeFreeze + +thaw :: forall h. ImmutableBuffer -> ST h (STBuffer h) +thaw = Internal.copyAll + +unsafeThaw :: forall h. ImmutableBuffer -> ST h (STBuffer h) +unsafeThaw = Internal.unsafeThaw + +fromArray :: forall h. Array Int -> ST h (STBuffer h) +fromArray = Internal.fromArray + +fromString :: forall h. String -> Encoding -> ST h (STBuffer h) +fromString = Internal.fromString + +fromArrayBuffer :: forall h. ArrayBuffer -> ST h (STBuffer h) +fromArrayBuffer = Internal.fromArrayBuffer + +toArrayBuffer :: forall h. STBuffer h -> ST h ArrayBuffer +toArrayBuffer = Internal.toArrayBuffer + +read :: forall h. BufferValueType -> Int -> STBuffer h -> ST h Number +read = Internal.read + +readString :: forall h. Encoding -> Int -> Int -> STBuffer h -> ST h String +readString = Internal.readString + +toString :: forall h. Encoding -> STBuffer h -> ST h String +toString = Internal.toString + +write :: forall h. BufferValueType -> Number -> Int -> STBuffer h -> ST h Unit +write = Internal.write + +writeString :: forall h. Encoding -> Int -> Int -> String -> STBuffer h -> ST h Int +writeString = Internal.writeString + +toArray :: forall h. STBuffer h -> ST h (Array Int) +toArray = Internal.toArray + +getAtOffset :: forall h. Int -> STBuffer h -> ST h (Maybe Int) +getAtOffset = Internal.getAtOffset + +setAtOffset :: forall h. Int -> Int -> STBuffer h -> ST h Unit +setAtOffset = Internal.setAtOffset + +slice :: forall h. Int -> Int -> STBuffer h -> STBuffer h +slice = Internal.slice + +size :: forall h. STBuffer h -> ST h Int +size = Internal.size + +concat :: forall h. Array (STBuffer h) -> ST h (STBuffer h) +concat = Internal.concat + +concat' :: forall h. Array (STBuffer h) -> Int -> ST h (STBuffer h) +concat' = Internal.concat' + +copy :: forall h. Int -> Int -> STBuffer h -> Int -> STBuffer h -> ST h Int +copy = Internal.copy + +fill :: forall h. Int -> Int -> Int -> STBuffer h -> ST h Unit +fill = Internal.fill diff --git a/test/Test/Node/Buffer/Class.purs b/test/Test/Node/Buffer/Class.purs index 7ebd53e..f837951 100644 --- a/test/Test/Node/Buffer/Class.purs +++ b/test/Test/Node/Buffer/Class.purs @@ -7,7 +7,8 @@ import Data.Maybe (Maybe(..)) import Data.Traversable (traverse) import Effect (Effect) import Effect.Console (log) -import Node.Buffer (class MutableBuffer, BufferValueType(..), concat', copy, create, fill, freeze, fromArray, fromArrayBuffer, fromString, getAtOffset, read, readString, setAtOffset, slice, thaw, toArray, toArrayBuffer, toString, write) +import Node.Buffer.Class (class MutableBuffer, concat', copy, create, fill, freeze, fromArray, fromArrayBuffer, fromString, getAtOffset, read, readString, setAtOffset, slice, thaw, toArray, toArrayBuffer, toString, write) +import Node.Buffer (BufferValueType(..)) import Node.Buffer.Immutable as Immutable import Node.Encoding (Encoding(..)) import Test.Assert (assertEqual) diff --git a/test/Test/Node/Buffer/ST.purs b/test/Test/Node/Buffer/ST.purs index 399b715..4e369b6 100644 --- a/test/Test/Node/Buffer/ST.purs +++ b/test/Test/Node/Buffer/ST.purs @@ -2,7 +2,6 @@ module Test.Node.Buffer.ST (test) where import Prelude -import Control.Monad.ST (run) as ST import Effect (Effect) import Effect.Console (log) import Node.Buffer.Class (create)