on master help sign in
encode as unfold; added trivial encodeFile
commitb9a6cb1cafa6018e648945070a2ef150d1f87c85 authorMichael Snoyman <michael@snoyman.com> dateTue 12 Jan 2010, 13:52 (17 years ago) parent2cdd30d
3 files changed+99−62
Text/Libyaml.hs+53−58 runtests.hs+44 yaml.cabal+2−4
Text/Libyaml.hs+53−58
@@ -19,7 +19,7 @@ module Text.Libyaml
1919 -- * Higher level functions
2020 , encode
2121 , decode
22− -- FIXME , encodeFile
22+ , encodeFile
2323 , decodeFile
2424 ) where
2525
@@ -33,9 +33,6 @@ import Foreign.Ptr
3333import Foreign.ForeignPtr
3434import Foreign.Marshal.Alloc
3535
36−import Control.Applicative
37−import Control.Failure
38−
3936import Control.Exception (throwIO, Exception)
4037import Data.Typeable (Typeable)
4138
@@ -213,9 +210,8 @@ makeString f a = do
213210 cchar <- castPtr `fmap` f a
214211 peekCString cchar
215212
216−parserParseOne :: MonadFailure YamlException m
217− => Parser
218− -> IO (m Event)
213+parserParseOne :: Parser
214+ -> IO (Either YamlException Event)
219215parserParseOne parser = withEventRaw $ \er -> do
220216 res <- c_yaml_parser_parse parser er
221217 event <-
@@ -225,9 +221,9 @@ parserParseOne parser = withEventRaw $ \er -> do
225221 context <- makeString c_get_parser_error_context parser
226222 offset <- fromIntegral `fmap`
227223 c_get_parser_error_offset parser
228− return $ failure $
224+ return $ Left $
229225 YamlParserException problem context offset
230− else return `fmap` getEvent er
226+ else Right `fmap` getEvent er
231227 c_yaml_event_delete er
232228 return event
233229
@@ -296,19 +292,6 @@ getEvent er = do
296292 YamlMappingStartEvent -> return EventMappingStart
297293 YamlMappingEndEvent -> return EventMappingEnd
298294
299−data YAttempt v = YSuccess v | YFailure YamlException
300−instance Functor YAttempt where
301− fmap = liftM
302−instance Applicative YAttempt where
303− pure = return
304− (<*>) = ap
305−instance Monad YAttempt where
306− return = YSuccess
307− YSuccess v >>= f = f v
308− YFailure e >>= _ = YFailure e
309−instance Failure YamlException YAttempt where
310− failure = YFailure
311−
312295parserParse :: (a -> Event -> Either a a)
313296 -> a
314297 -> Parser
@@ -316,8 +299,8 @@ parserParse :: (a -> Event -> Either a a)
316299parserParse fold accum parser = do
317300 event' <- parserParseOne parser
318301 case event' of
319− YFailure e -> return $ Left e
320− YSuccess event -> do
302+ Left e -> return $ Left e
303+ Right event -> do
321304 case fold accum event of
322305 Left accum' -> return $ Right accum'
323306 Right accum' -> parserParse fold accum' parser
@@ -349,34 +332,34 @@ foreign import ccall unsafe "get_buffer_buff"
349332foreign import ccall unsafe "get_buffer_used"
350333 c_get_buffer_used :: Buffer -> IO CULong
351334
352−withBuffer :: MonadFailure YamlException m
353− => (Buffer -> IO (YAttempt ()))
354− -> IO (m B.ByteString)
335+withBuffer :: (Buffer -> IO (Either YamlException ()))
336+ -> IO (Either YamlException B.ByteString)
355337withBuffer f = allocaBytes bufferSize $ \b -> do
356338 c_buffer_init b
357339 aRes <- f b
358340 case aRes of
359− YFailure e -> return $ failure e
360− YSuccess () -> do
341+ Left e -> return $ Left e
342+ Right () -> do
361343 ptr' <- c_get_buffer_buff b
362344 len <- c_get_buffer_used b
363345 fptr <- newForeignPtr_ $ castPtr ptr'
364− return $ return $ B.fromForeignPtr fptr 0 $ fromIntegral len
346+ return $ Right $ B.fromForeignPtr fptr 0 $ fromIntegral len
365347
366348foreign import ccall unsafe "my_emitter_set_output"
367349 c_my_emitter_set_output :: Emitter -> Buffer -> IO ()
368350
369−withEmitter :: MonadFailure YamlException m
370− => (Emitter -> IO (YAttempt ()))
371− -> IO (m B.ByteString)
351+withEmitter :: (Emitter -> IO (Either YamlException ()))
352+ -> IO (Either YamlException B.ByteString)
372353withEmitter f = allocaBytes emitterSize $ \e -> do
373− res <- c_yaml_emitter_initialize e
374− when (res == 0) $ throwIO YamlOutOfMemory
375− bs <- withBuffer $ \b -> do
376− c_my_emitter_set_output e b
377− f e
378− c_yaml_emitter_delete e
379− return bs
354+ res <- c_yaml_emitter_initialize e
355+ if res == 0
356+ then return $ Left YamlOutOfMemory
357+ else do
358+ bs <- withBuffer $ \b -> do
359+ c_my_emitter_set_output e b
360+ f e
361+ c_yaml_emitter_delete e
362+ return bs
380363
381364foreign import ccall unsafe "yaml_emitter_emit"
382365 c_yaml_emitter_emit :: Emitter -> EventRaw -> IO CInt
@@ -384,18 +367,20 @@ foreign import ccall unsafe "yaml_emitter_emit"
384367foreign import ccall unsafe "get_emitter_error"
385368 c_get_emitter_error :: Emitter -> IO (Ptr CUChar)
386369
387−emitEvents :: MonadFailure YamlException m
388− => Emitter
389− -> [Event]
390− -> IO (m ())
391−emitEvents _ [] = return $ return ()
392−emitEvents emitter (e:rest) = do
393− res <- toEventRaw e $ c_yaml_emitter_emit emitter
394− if res == 0
395− then do
396− problem <- makeString c_get_emitter_error emitter
397− return $ failure $ YamlEmitterException problem
398− else emitEvents emitter rest
370+emitEvents :: (a -> Maybe (Event, a))
371+ -> a
372+ -> Emitter
373+ -> IO (Either YamlException ())
374+emitEvents unfold src emitter = do
375+ case unfold src of
376+ Nothing -> return $ Right ()
377+ Just (e, src') -> do
378+ res <- toEventRaw e $ c_yaml_emitter_emit emitter
379+ if res == 0
380+ then do
381+ problem <- makeString c_get_emitter_error emitter
382+ return $ Left $ YamlEmitterException problem
383+ else emitEvents unfold src' emitter
399384
400385foreign import ccall unsafe "yaml_stream_start_event_initialize"
401386 c_yaml_stream_start_event_initialize :: EventRaw -> CInt -> IO CInt
@@ -500,19 +485,29 @@ toEventRaw e f = withEventRaw $ \er -> do
500485 c_yaml_mapping_end_event_initialize er
501486 EventAlias -> error "toEventRaw: EventAlias not supported"
502487 EventNone -> error "toEventRaw: EventNone not supported"
503− unless (ret == 1) $ failure $ ToEventRawException ret
488+ unless (ret == 1) $ throwIO $ ToEventRawException ret
504489 f er
505490
506491newtype ToEventRawException = ToEventRawException CInt
507492 deriving (Show, Typeable)
508493instance Exception ToEventRawException
509494
510−encode :: MonadFailure YamlException m
511− => [Event]
512− -> IO (m B.ByteString)
513−encode = withEmitter . flip emitEvents
495+encode :: (a -> Maybe (Event, a))
496+ -> a
497+ -> IO (Either YamlException B.ByteString)
498+encode unfold src = withEmitter $ emitEvents unfold src
514499
515−-- FIXME encodeFile
500+encodeFile :: FilePath
501+ -> (a -> Maybe (Event, a))
502+ -> a
503+ -> IO (Either YamlException ())
504+encodeFile filePath unfold src = do
505+ res <- withEmitter $ emitEvents unfold src
506+ case res of
507+ Left e -> return $ Left e
508+ Right bs -> do
509+ Data.ByteString.writeFile filePath bs
510+ return $ Right ()
516511
517512decode :: B.ByteString
518513 -> (a -> Event -> Either a a)
runtests.hs+44
@@ -2,6 +2,7 @@ import Test.Framework (defaultMain)
22
33import Text.Libyaml
44import qualified Data.ByteString.Char8 as B8
5+import Control.Exception
56
67--import Test.Framework (testGroup, Test)
78import Test.Framework.Providers.HUnit
@@ -13,6 +14,8 @@ main :: IO ()
1314main = defaultMain
1415 [ testCase "count scalars" caseCountScalars
1516 , testCase "largest string" caseLargestString
17+ , testCase "encode/decode" caseEncodeDecode
18+ , testCase "encode/decode file" caseEncodeDecodeFile
1619 ]
1720
1821caseCountScalars :: Assertion
@@ -45,3 +48,44 @@ caseLargestString = do
4548 fold res EventNone = Left res
4649 fold res _ = Right res
4750 accum = (0, "no strings found")
51+
52+toIO :: Exception l => IO (Either l r) -> IO r
53+toIO x = x >>= either throwIO return
54+
55+caseEncodeDecode :: Assertion
56+caseEncodeDecode = do
57+ eList' <- toIO $ decode yamlBS fold id
58+ let eList = eList' []
59+ bs <- toIO $ encode unfold eList
60+ eList2' <- toIO $ decode bs fold id
61+ let eList2 = eList2' []
62+ map MyEvent eList @=? map MyEvent eList2
63+ where
64+ yamlString = "foo: bar\nbaz:\n - bin1\n - bin2\n"
65+ yamlBS = B8.pack yamlString
66+ fold x EventNone = Left x
67+ fold x e = Right $ x . (:) e
68+ unfold (x:xs) = Just (x, xs)
69+ unfold [] = Nothing
70+
71+caseEncodeDecodeFile :: Assertion
72+caseEncodeDecodeFile = do
73+ eList' <- toIO $ decodeFile filePath fold id
74+ let eList = eList' []
75+ toIO $ encodeFile tmpPath unfold eList
76+ eList2' <- toIO $ decodeFile tmpPath fold id
77+ let eList2 = eList2' []
78+ map MyEvent eList @=? map MyEvent eList2
79+ where
80+ filePath = "test/largest-string.yaml"
81+ tmpPath = "tmp.yaml"
82+ fold x EventNone = Left x
83+ fold x e = Right $ x . (:) e
84+ unfold (x:xs) = Just (x, xs)
85+ unfold [] = Nothing
86+
87+newtype MyEvent = MyEvent Event deriving Show
88+instance Eq MyEvent where
89+ (MyEvent (EventScalar s t _)) == (MyEvent (EventScalar s' t' _)) =
90+ s == s' && t == t'
91+ MyEvent e1 == MyEvent e2 = e1 == e2
yaml.cabal+2−4
@@ -28,8 +28,7 @@ library
2828 else
2929 Buildable: True
3030 build-depends: base >= 4 && < 5,
31− bytestring >= 0.9.1.4 && < 0.10,
32− failure >= 0.0.0 && < 0.1
31+ bytestring >= 0.9.1.4 && < 0.10
3332 exposed-modules: Text.Libyaml
3433 ghc-options: -Wall
3534 c-sources: c/helper.c,
@@ -53,8 +52,7 @@ executable runtests
5352 HUnit,
5453 QuickCheck >= 1 && < 2,
5554 base >= 4 && < 5,
56− bytestring >= 0.9.1.4 && < 0.10,
57− failure >= 0.0.0 && < 0.1
55+ bytestring >= 0.9.1.4 && < 0.10
5856 else
5957 Buildable: False
6058 ghc-options: -Wall