ghcjs / ghcjs-base

base library for GHCJS for JavaScript interaction and marshalling, used by higher level libraries like JSC
MIT License
45 stars 67 forks source link

fromByteString produces a null Buffer when the ByteString is empty #49

Open ryantrinkle opened 8 years ago

ryantrinkle commented 8 years ago

This program:

{-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI #-}

import qualified Data.ByteString as BS
import GHCJS.Types
import GHCJS.Buffer

main :: IO ()
main = do
  let (b, _, _) = fromByteString BS.empty
  consoleLog $ jsval $ getArrayBuffer b

foreign import javascript safe "console.log($1)" consoleLog :: JSVal -> IO ()

produces the following error:

uncaught exception in Haskell main thread: TypeError: Cannot read property 'buf' of null
TypeError: Cannot read property 'buf' of null
    at h$$k4 (/home/ryan/try-reflex22/fromByteStringIssue.jsexe/all.js:37401:57)
    at h$runThreadSlice (/home/ryan/try-reflex22/fromByteStringIssue.jsexe/all.js:9790:11)
    at h$runThreadSliceCatch (/home/ryan/try-reflex22/fromByteStringIssue.jsexe/all.js:9741:12)
    at Immediate.h$mainLoop (/home/ryan/try-reflex22/fromByteStringIssue.jsexe/all.js:9736:9)
    at processImmediate [as _immediateCallback] (timers.js:374:17)

But, when the BS.empty is replaced with a non-empty ByteString, it outputs

ArrayBuffer {}

as expected.

luite commented 8 years ago

Hmm, good catch. GHCJS does not allocate a buffer of size 0 for empty buffers.

GHC HEAD also adds some resizable ByteArray# operations, which may make it necessary to move getArrayBuffer into IO. Should it throw an exception when there's no buffer? should it return a Maybe or Nullable type instead? or perhaps return a dummy buffer?

ryantrinkle commented 8 years ago

in my use case, I need to send the buffer along to WebSocket's send method, so I need a dummy, ultimately. However, I don't mind converting from Maybe/Nullable as necessary - whatever makes the most sense to you (or has the best performance) is fine with me.

ryantrinkle commented 8 years ago

The code where I encountered this is here: https://github.com/ryantrinkle/reflex-dom/blob/ghcjs-improved-base-2/src-ghcjs/Reflex/Dom/WebSocket/Foreign.hs#L38