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