@@ -0,0 +1,75 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{- |
3+ Module : Text.Pandoc.Lua.Marshaling.MediaBag
4+ Copyright : © 2012-2019 John MacFarlane
5+ © 2017-2019 Albert Krewinkel
6+ License : GNU GPL, version 2 or above
7+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
8+ Stability : alpha
9+
10+Instances to marshal (push) and unmarshal (peek) media data.
11+-}
12+module Text.Pandoc.Lua.Marshaling.MediaBag (pushIterator) where
13+
14+import Prelude
15+import Foreign.Ptr (Ptr)
16+import Foreign.StablePtr (StablePtr, deRefStablePtr, newStablePtr)
17+import Foreign.Lua (Lua, NumResults, Peekable, Pushable, StackIndex)
18+import Foreign.Lua.Types.Peekable (reportValueOnFailure)
19+import Foreign.Lua.Userdata (ensureUserdataMetatable, pushAnyWithMetatable,
20+ toAnyWithName)
21+import Text.Pandoc.MediaBag (MediaBag, mediaItems)
22+import Text.Pandoc.MIME (MimeType)
23+import Text.Pandoc.Lua.Marshaling.AnyValue (AnyValue (..))
24+
25+import qualified Data.ByteString.Lazy as BL
26+import qualified Foreign.Lua as Lua
27+import qualified Foreign.Storable as Storable
28+
29+-- | A list of 'MediaBag' items.
30+newtype MediaItems = MediaItems [(String, MimeType, BL.ByteString)]
31+
32+instance Pushable MediaItems where
33+ push = pushMediaItems
34+
35+instance Peekable MediaItems where
36+ peek = peekMediaItems
37+
38+-- | Push an iterator triple to be used with Lua's @for@ loop construct.
39+-- Each iterator invokation returns a tripple consisting of an item's
40+-- filename, MIME type, and content.
41+pushIterator :: MediaBag -> Lua NumResults
42+pushIterator mb = do
43+ Lua.pushHaskellFunction nextItem
44+ Lua.push (MediaItems $ mediaItems mb)
45+ Lua.pushnil
46+ return 3
47+
48+-- | Lua type name for @'MediaItems'@.
49+mediaItemsTypeName :: String
50+mediaItemsTypeName = "pandoc MediaItems"
51+
52+-- | Push a @MediaItems@ element to the stack.
53+pushMediaItems :: MediaItems -> Lua ()
54+pushMediaItems xs = pushAnyWithMetatable pushMT xs
55+ where
56+ pushMT = ensureUserdataMetatable mediaItemsTypeName (return ())
57+
58+-- | Retrieve a @MediaItems@ element from the stack.
59+peekMediaItems :: StackIndex -> Lua MediaItems
60+peekMediaItems = reportValueOnFailure mediaItemsTypeName
61+ (`toAnyWithName` mediaItemsTypeName)
62+
63+-- | Retrieve a list of items from an iterator state, return the first
64+-- item (if present), and advance the state.
65+nextItem :: Ptr (StablePtr MediaItems) -> AnyValue -> Lua NumResults
66+nextItem ptr _ = do
67+ (MediaItems items) <- Lua.liftIO $ deRefStablePtr =<< Storable.peek ptr
68+ case items of
69+ [] -> 2 <$ (Lua.pushnil *> Lua.pushnil)
70+ (key, mt, content):xs -> do
71+ Lua.liftIO $ Storable.poke ptr =<< newStablePtr (MediaItems xs)
72+ Lua.push key
73+ Lua.push mt
74+ Lua.push content
75+ return 3