module GHCJS.Buffer
( Buffer
, MutableBuffer
, create
, createFromArrayBuffer
, thaw, freeze, clone
, byteLength
, getArrayBuffer
, getUint8Array
, getUint16Array
, getInt32Array
, getDataView
, getFloat32Array
, getFloat64Array
, toByteString, fromByteString
) where
import GHCJS.Buffer.Types
import Control.Lens.Operators ((^.))
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base64 as B64 (encode, decode)
import Data.Text.Encoding (encodeUtf8, decodeUtf8)
import qualified JavaScript.TypedArray.Internal.Types as I
import JavaScript.TypedArray.ArrayBuffer.Internal (SomeArrayBuffer(..))
import JavaScript.TypedArray.DataView.Internal (SomeDataView(..))
import GHCJS.Marshal (FromJSVal(..))
import Language.Javascript.JSaddle.Types (JSM, GHCJSPure(..), ghcjsPure)
import Language.Javascript.JSaddle.Object (js, js2, jsg1, jsg3)
create :: Int -> JSM MutableBuffer
create n | n >= 0 = SomeBuffer <$> jsg1 "h$newByteArray" n
| otherwise = error "create: negative size"
{-# INLINE create #-}
createFromArrayBuffer :: SomeArrayBuffer any -> GHCJSPure (SomeBuffer any)
createFromArrayBuffer (SomeArrayBuffer buf) = GHCJSPure $ SomeBuffer <$> jsg1 "h$wrapBuffer" buf
{-# INLINE createFromArrayBuffer #-}
getArrayBuffer :: SomeBuffer any -> GHCJSPure (SomeArrayBuffer any)
getArrayBuffer (SomeBuffer buf) = GHCJSPure $ SomeArrayBuffer <$> buf ^. js "buf"
{-# INLINE getArrayBuffer #-}
getInt32Array :: SomeBuffer any -> GHCJSPure (I.SomeInt32Array any)
getInt32Array (SomeBuffer buf) = GHCJSPure $ I.SomeTypedArray <$> buf ^. js "i3"
{-# INLINE getInt32Array #-}
getUint8Array :: SomeBuffer any -> GHCJSPure (I.SomeUint8Array any)
getUint8Array (SomeBuffer buf) = GHCJSPure $ I.SomeTypedArray <$> buf ^. js "u8"
{-# INLINE getUint8Array #-}
getUint16Array :: SomeBuffer any -> GHCJSPure (I.SomeUint16Array any)
getUint16Array (SomeBuffer buf) = GHCJSPure $ I.SomeTypedArray <$> buf ^. js "u1"
{-# INLINE getUint16Array #-}
getFloat32Array :: SomeBuffer any -> GHCJSPure (I.SomeFloat32Array any)
getFloat32Array (SomeBuffer buf) = GHCJSPure $ I.SomeTypedArray <$> buf ^. js "f3"
{-# INLINE getFloat32Array #-}
getFloat64Array :: SomeBuffer any -> GHCJSPure (I.SomeFloat64Array any)
getFloat64Array (SomeBuffer buf) = GHCJSPure $ I.SomeTypedArray <$> buf ^. js "f6"
{-# INLINE getFloat64Array #-}
getDataView :: SomeBuffer any -> GHCJSPure (SomeDataView any)
getDataView (SomeBuffer buf) = GHCJSPure $ SomeDataView <$> buf ^. js "dv"
{-# INLINE getDataView #-}
freeze :: MutableBuffer -> JSM Buffer
freeze = js_clone
{-# INLINE freeze #-}
thaw :: Buffer -> JSM MutableBuffer
thaw = js_clone
{-# INLINE thaw #-}
clone :: MutableBuffer -> JSM (SomeBuffer any2)
clone = js_clone
{-# INLINE clone #-}
fromByteString :: ByteString -> GHCJSPure (Buffer, Int, Int)
fromByteString bs = GHCJSPure $ do
buffer <- SomeBuffer <$> jsg1 "h$newByteArrayFromBase64String" (decodeUtf8 $ B64.encode bs)
return (buffer, 0, BS.length bs)
{-# INLINE fromByteString #-}
toByteString :: Int -> Maybe Int -> Buffer -> GHCJSPure ByteString
toByteString off mbLen buf = GHCJSPure $ do
bufLen <- ghcjsPure $ byteLength buf
case mbLen of
_ | off < 0 -> error "toByteString: negative offset"
| off > bufLen -> error "toByteString: offset past end of buffer"
Just len | len < 0 -> error "toByteString: negative length"
| len > bufLen - off -> error "toByteString: length past end of buffer"
| otherwise -> ghcjsPure $ unsafeToByteString off len buf
Nothing -> ghcjsPure $ unsafeToByteString off (bufLen - off) buf
unsafeToByteString :: Int -> Int -> Buffer -> GHCJSPure ByteString
unsafeToByteString off len (SomeBuffer buf) = GHCJSPure $ do
b64 <- jsg3 "h$byteArrayToBase64String" off len buf >>= fromJSValUnchecked
return $ case B64.decode (encodeUtf8 b64) of
Left err -> error $ "unsafeToByteString base 64 decode error :" ++ err
Right bs -> bs
byteLength :: SomeBuffer any -> GHCJSPure Int
byteLength (SomeBuffer buf) = GHCJSPure $ buf ^. js "len" >>= fromJSValUnchecked
{-# INLINE byteLength #-}
js_clone :: SomeBuffer any1 -> JSM (SomeBuffer any2)
js_clone (SomeBuffer buf) = SomeBuffer <$> jsg1 "h$wrapBuffer" (buf ^. js "buf" ^. js2 "slice" (buf ^. js "u8" ^. js "byteOffset") (buf ^. js "len"))