@@ -41,8 +41,9 @@ import Control.Monad.IO.Class
41import Control.Monad.Trans.Class (lift)
41import Control.Monad.Trans.Class (lift)
43import Control.Exception (throwIO, Exception, finally)
43import Control.Exception (throwIO, Exception, finally)
44−import Data.Enumerator
45import Control.Applicative
44import Control.Applicative
45+import Control.Monad.Trans.Resource
46+import qualified Data.Conduit as C
47data Event =
48data Event =
48 EventStreamStart
49 EventStreamStart
@@ -120,8 +121,8 @@ eventSize = 104
120foreign import ccall unsafe "yaml_parser_initialize"
121foreign import ccall unsafe "yaml_parser_initialize"
121 c_yaml_parser_initialize :: Parser -> IO CInt
122 c_yaml_parser_initialize :: Parser -> IO CInt
123−foreign import ccall unsafe "&yaml_parser_delete"
124+foreign import ccall unsafe "yaml_parser_delete"
124− c_yaml_parser_delete :: FunPtr (Parser -> IO ())
125+ c_yaml_parser_delete :: Parser -> IO ()
126foreign import ccall unsafe "yaml_parser_set_input_string"
127foreign import ccall unsafe "yaml_parser_set_input_string"
127 c_yaml_parser_set_input_string :: Parser
128 c_yaml_parser_set_input_string :: Parser
@@ -146,8 +147,8 @@ foreign import ccall unsafe "fclose"
146 c_fclose :: File
147 c_fclose :: File
149−foreign import ccall unsafe "&fclose_helper"
150+foreign import ccall unsafe "fclose_helper"
150− c_fclose_helper :: FunPtr (File -> Parser -> IO ())
151+ c_fclose_helper :: File -> IO ()
152withForeignPtr' :: MonadIO m => ForeignPtr a -> (Ptr a -> m b) -> m b
153withForeignPtr' :: MonadIO m => ForeignPtr a -> (Ptr a -> m b) -> m b
153withForeignPtr' fp f = do
154withForeignPtr' fp f = do
@@ -455,60 +456,67 @@ newtype ToEventRawException = ToEventRawException CInt
455 deriving (Show, Typeable)
456 deriving (Show, Typeable)
456instance Exception ToEventRawException
457instance Exception ToEventRawException
458−decode :: MonadIO m => B.ByteString -> Enumerator Event m a
459+decode :: ResourceIO m => B.ByteString -> C.Source m Event
459−decode bs i = do
460+decode bs =
460− fp <- liftIO $ mallocForeignPtrBytes parserSize
461+ C.sourceIO alloc cleanup (runParser . fst)
461− res <- liftIO $ withForeignPtr fp c_yaml_parser_initialize
462+ where
462− liftIO $ addForeignPtrFinalizer c_yaml_parser_delete fp
463+ alloc = mask_ $ do
463− a <-
464+ ptr <- mallocBytes parserSize
465+ res <- c_yaml_parser_initialize ptr
464− if (res == 0)
466+ if res == 0
468+ c_yaml_parser_delete ptr
465− then throwError $ YamlException "Yaml out of memory"
470+ throwIO $ YamlException "Yaml out of memory"
466− else do -- NOTE: can't replace the following with unsafeUseAsCString
471+ else do
467− -- since it must run in a MonadIO
468− let (fptr, offset, len) = B.toForeignPtr bs
472+ let (bsfptr, offset, len) = B.toForeignPtr bs
469− withForeignPtr' fptr $ \ptr -> do
473+ let bsptrOrig = unsafeForeignPtrToPtr bsfptr
470− let ptr' = castPtr ptr `plusPtr` offset
474+ let bsptr = castPtr bsptrOrig `plusPtr` offset
471− len' = fromIntegral len
475+ c_yaml_parser_set_input_string ptr bsptr (fromIntegral len)
472− liftIO $ withForeignPtr fp $ \p ->
476+ return (ptr, bsfptr)
473− c_yaml_parser_set_input_string p ptr' len'
477+ cleanup (ptr, bsfptr) = do
474− runParser fp i
478+ touchForeignPtr bsfptr
475− return a
479+ c_yaml_parser_delete ptr
477−decodeFile :: MonadIO m => FilePath -> Enumerator Event m a
482+decodeFile :: ResourceIO m => FilePath -> C.Source m Event
478−decodeFile file i = do
483+decodeFile file =
479− fp <- liftIO $ mallocForeignPtrBytes parserSize
484+ C.sourceIO alloc cleanup (runParser . fst)
480− liftIO $ addForeignPtrFinalizer c_yaml_parser_delete fp
485+ where
487+ ptr <- mallocBytes parserSize
481− res <- liftIO $ withForeignPtr fp c_yaml_parser_initialize
488+ res <- c_yaml_parser_initialize ptr
483− if res == 0
489+ if res == 0
491+ c_yaml_parser_delete ptr
484− then throwError $ YamlException "Yaml out of memory"
493+ throwIO $ YamlException "Yaml out of memory"
486− file' <- liftIO
495+ file' <- liftIO
487− $ withCString file $ \file' -> withCString "r" $ \r' ->
496+ $ withCString file $ \file' -> withCString "r" $ \r' ->
488− c_fopen file' r'
497+ c_fopen file' r'
489− liftIO $ addForeignPtrFinalizerEnv c_fclose_helper file' fp
490− if (file' == nullPtr)
498+ if file' == nullPtr
500+ c_fclose_helper file'
501+ c_yaml_parser_delete ptr
491− then throwError $ YamlException
503+ throwIO $ YamlException
492− $ "Yaml file not found: " ++ file
504+ $ "Yaml file not found: " ++ file
494− liftIO $ withForeignPtr fp $ \p ->
495− c_yaml_parser_set_input_file p file'
506+ c_yaml_parser_set_input_file ptr file'
496− a <- runParser fp i
507+ return (ptr, file')
497− return a
508+ cleanup (ptr, file') = do
498− return a
509+ c_fclose_helper file'
499−
510+ c_yaml_parser_delete ptr
500−runParser :: MonadIO m
511+ free ptr
501− => ForeignPtr ParserStruct
512+
502− -> Enumerator Event m a
513+runParser :: ResourceIO m => Parser -> m (C.SourceResult Event)
503−runParser fp (Continue k) = do
514+runParser parser = liftIO $ do
504− e <- liftIO $ withForeignPtr fp parserParseOne'
515+ e <- parserParseOne' parser
505 case e of
516 case e of
506− Left err -> throwError $ YamlException err
517+ Left err -> throwIO $ YamlException err
507− Right Nothing -> continue k
518+ Right Nothing -> return $ C.Closed
508− Right (Just ev) -> do
519+ Right (Just ev) -> return $ C.Open ev
509− step' <- lift $ runIteratee $ k $ Chunks [ev]
511−runParser _ step = returnI step
513parserParseOne' :: Parser
521parserParseOne' :: Parser
514 -> IO (Either String (Maybe Event))
522 -> IO (Either String (Maybe Event))
@@ -529,57 +537,60 @@ parserParseOne' parser = allocaBytes eventSize $ \er -> do
529 , show offset
537 , show offset
532− else liftIO $ Right <$> getEvent er
540+ else Right <$> getEvent er
534−encode :: MonadIO m => Iteratee Event m B.ByteString
542+encode :: ResourceIO m => C.Sink Event m ByteString
535−encode = do
543+encode =
536− fp <- liftIO $ mallocForeignPtrBytes emitterSize
537− res <- liftIO $ withForeignPtr fp c_yaml_emitter_initialize
538− when (res == 0) $ throwError
539− $ YamlException "c_yaml_emitter_initialize failed"
540− buf <- liftIO $ mallocForeignPtrBytes bufferSize
541− liftIO $ withForeignPtr buf c_buffer_init
542− liftIO $ withForeignPtr fp $
543− \emitter -> withForeignPtr buf $
544− \b -> c_my_emitter_set_output emitter b
545− runEmitter (go buf) fp
544+ runEmitter alloc close
547− go buf = withForeignPtr buf $ \b -> do
546+ alloc emitter = do
547+ fbuf <- mallocForeignPtrBytes bufferSize
548+ withForeignPtr fbuf c_buffer_init
549+ withForeignPtr fbuf $ c_my_emitter_set_output emitter
551+ close fbuf = withForeignPtr fbuf $ \b -> do
548 ptr' <- c_get_buffer_buff b
552 ptr' <- c_get_buffer_buff b
549 len <- c_get_buffer_used b
553 len <- c_get_buffer_used b
550 fptr <- newForeignPtr_ $ castPtr ptr'
554 fptr <- newForeignPtr_ $ castPtr ptr'
551 return $ B.fromForeignPtr fptr 0 $ fromIntegral len
555 return $ B.fromForeignPtr fptr 0 $ fromIntegral len
553−encodeFile :: MonadIO m
557+encodeFile :: ResourceIO m
554 => FilePath
558 => FilePath
555− -> Iteratee Event m ()
559+ -> C.Sink Event m ()
556−encodeFile filePath = do
560+encodeFile filePath = C.Sink $ do
557− fp <- liftIO $ mallocForeignPtrBytes emitterSize
561+ (releaseKey, file) <- flip withIO c_fclose $ do
558− res <- liftIO $ withForeignPtr fp c_yaml_emitter_initialize
559− when (res == 0) $ throwError
560− $ YamlException "c_yaml_emitter_initialize failed"
561− file <- liftIO $ withCString filePath $
562+ file <- liftIO $ withCString filePath $
562− \filePath' -> withCString "w" $
563+ \filePath' -> withCString "w" $
563− \w' -> c_fopen filePath' w'
564+ \w' -> c_fopen filePath' w'
564− when (file == nullPtr) $ throwError
565+ if (file == nullPtr)
565− $ YamlException $ "could not open file for write: " ++ filePath
566+ then throwIO $ YamlException $ "could not open file for write: " ++ filePath
568+ C.prepareSink $ runEmitter (alloc file) (return) -- FIXME close file early
570+ alloc file emitter = do
566− liftIO $ withForeignPtr fp $ flip c_yaml_emitter_set_output_file file
571+ c_yaml_emitter_set_output_file emitter file
567− runEmitter (c_fclose file) fp
572+ return ()
569−runEmitter :: MonadIO m
574+runEmitter :: ResourceIO m
570− => IO a
575+ => (Emitter -> IO a) -- ^ alloc
571− -> ForeignPtr EmitterStruct
576+ -> (a -> IO b) -- ^ close
572− -> Iteratee Event m a
577+ -> C.Sink Event m b
573−runEmitter close fp = continue go
578+runEmitter allocI closeI =
579+ C.sinkIO alloc cleanup push close
575− go EOF = do
581+ alloc = mask_ $ do
582+ emitter <- mallocBytes emitterSize
583+ res <- c_yaml_emitter_initialize emitter
584+ when (res == 0) $ throwIO $ YamlException "c_yaml_emitter_initialize failed"
587+ cleanup (emitter, _) = do
576− liftIO $ withForeignPtr fp c_yaml_emitter_delete
588+ c_yaml_emitter_delete emitter
577− a <- liftIO close
589+ free emitter
578− yield a EOF
590+ push (emitter, _) e = do
580− liftIO $ withForeignPtr fp $ \emitter ->
581− mapM_ (\e -> toEventRaw e $ c_yaml_emitter_emit emitter) c
591+ liftIO $ toEventRaw e $ c_yaml_emitter_emit emitter
582− continue go
592+ return C.Processing
593+ close (_, a) = liftIO $ closeI a
584data YamlException = YamlException String
595data YamlException = YamlException String
585 deriving (Show, Typeable)
596 deriving (Show, Typeable)