rawToGVal :: MonadIO m => RawBytes -> GVal (Run p m h)
rawToGVal raw =
    dict
        [ ("length", Ginger.fromFunction (gfnLength raw))
        , ("read", Ginger.fromFunction (gfnRead raw))
        , ("store", Ginger.fromFunction (gfnStore raw))
        ]
    where
        gfnLength :: MonadIO m => RawBytes -> [(Maybe Text, GVal (Run p m h))] -> Run p m h (GVal (Run p m h))
        gfnLength raw args = do
            length <- liftIO (rbLength raw)
            return . toGVal $ length
        gfnRead :: MonadIO m => RawBytes -> [(Maybe Text, GVal (Run p m h))] -> Run p m h (GVal (Run p m h))
        gfnRead raw args = do
            inputLength <- liftIO (rbLength raw)
            let extracted =
                    Ginger.extractArgsDefL
                        [ ("start", def)
                        , ("length", toGVal inputLength)
                        ]
                        args
            case extracted of
                Right [startG, lengthG] -> do
                    let start = fromMaybe 0 $ asInteger startG
                        length = fromMaybe inputLength $ asInteger lengthG
                    bytes <- liftIO (rbGetRange raw start length)
                    return $ (toGVal bytes) { Ginger.asBytes = Just (LBS.toStrict bytes) }
                _ -> throwError $ Ginger.ArgumentsError (Just "RawBytes.read") ""

        gfnStore :: MonadIO m => RawBytes -> [(Maybe Text, GVal (Run p m h))] -> Run p m h (GVal (Run p m h))
        gfnStore raw args = do
            let extracted =
                    Ginger.extractArgsDefL
                        [ ("filename", "stored")
                        ]
                        args
            case extracted of
                Right [filenameG] -> liftIO $ do
                    let filename = unpack . Ginger.asText $ filenameG
                    len <- rbLength raw
                    bytes <- rbGetRange raw 0 len
                    LBS8.writeFile filename bytes
                    return . toGVal $ True
                _ -> throwError $ Ginger.ArgumentsError (Just "RawBytes.store") ""

        asInteger :: GVal m -> Maybe Integer
        asInteger = fmap round . Ginger.asNumber
rawToGVal :: MonadIO m => RawBytes -> GVal (Run p m h)
rawToGVal raw =
    dict
        [ ("length", Ginger.fromFunction (gfnLength raw))
        , ("read", Ginger.fromFunction (gfnRead raw))
        , ("store", Ginger.fromFunction (gfnStore raw))
        ]
    where
        gfnLength :: MonadIO m => RawBytes -> [(Maybe Text, GVal (Run p m h))] -> Run p m h (GVal (Run p m h))
        gfnLength raw args = do
            length <- liftIO (rbLength raw)
            return . toGVal $ length
        gfnRead :: MonadIO m => RawBytes -> [(Maybe Text, GVal (Run p m h))] -> Run p m h (GVal (Run p m h))
        gfnRead raw args = do
            inputLength <- liftIO (rbLength raw)
            let extracted =
                    Ginger.extractArgsDefL
                        [ ("start", def)
                        , ("length", toGVal inputLength)
                        ]
                        args
            case extracted of
                Right [startG, lengthG] -> do
                    let start = fromMaybe 0 $ asInteger startG
                        length = fromMaybe inputLength $ asInteger lengthG
                    bytes <- liftIO (rbGetRange raw start length)
                    return $ (toGVal bytes) { Ginger.asBytes = Just (LBS.toStrict bytes) }
                _ -> throwError $ Ginger.ArgumentsError (Just "RawBytes.read") ""

        gfnStore :: MonadIO m => RawBytes -> [(Maybe Text, GVal (Run p m h))] -> Run p m h (GVal (Run p m h))
        gfnStore raw args = do
            let extracted =
                    Ginger.extractArgsDefL
                        [ ("filename", "stored")
                        ]
                        args
            case extracted of
                Right [filenameG] -> liftIO $ do
                    let filename = unpack . Ginger.asText $ filenameG
                    len <- rbLength raw
                    bytes <- rbGetRange raw 0 len
                    LBS8.writeFile filename bytes
                    return . toGVal $ True
                _ -> throwError $ Ginger.ArgumentsError (Just "RawBytes.store") ""

        asInteger :: GVal m -> Maybe Integer
        asInteger = fmap round . Ginger.asNumber
rawToGVal raw =
    dict
        [ ("length", Ginger.fromFunction (gfnLength raw))
        , ("read", Ginger.fromFunction (gfnRead raw))
        , ("store", Ginger.fromFunction (gfnStore raw))
        ]
    where
        gfnLength :: MonadIO m => RawBytes -> [(Maybe Text, GVal (Run p m h))] -> Run p m h (GVal (Run p m h))
        gfnLength raw args = do
            length <- liftIO (rbLength raw)
            return . toGVal $ length
        gfnRead :: MonadIO m => RawBytes -> [(Maybe Text, GVal (Run p m h))] -> Run p m h (GVal (Run p m h))
        gfnRead raw args = do
            inputLength <- liftIO (rbLength raw)
            let extracted =
                    Ginger.extractArgsDefL
                        [ ("start", def)
                        , ("length", toGVal inputLength)
                        ]
                        args
            case extracted of
                Right [startG, lengthG] -> do
                    let start = fromMaybe 0 $ asInteger startG
                        length = fromMaybe inputLength $ asInteger lengthG
                    bytes <- liftIO (rbGetRange raw start length)
                    return $ (toGVal bytes) { Ginger.asBytes = Just (LBS.toStrict bytes) }
                _ -> throwError $ Ginger.ArgumentsError (Just "RawBytes.read") ""

        gfnStore :: MonadIO m => RawBytes -> [(Maybe Text, GVal (Run p m h))] -> Run p m h (GVal (Run p m h))
        gfnStore raw args = do
            let extracted =
                    Ginger.extractArgsDefL
                        [ ("filename", "stored")
                        ]
                        args
            case extracted of
                Right [filenameG] -> liftIO $ do
                    let filename = unpack . Ginger.asText $ filenameG
                    len <- rbLength raw
                    bytes <- rbGetRange raw 0 len
                    LBS8.writeFile filename bytes
                    return . toGVal $ True
                _ -> throwError $ Ginger.ArgumentsError (Just "RawBytes.store") ""

        asInteger :: GVal m -> Maybe Integer
        asInteger = fmap round . Ginger.asNumber