git.iko.soy/typeable/pandoc
on master help sign in
Lua filter internals: push Shared.Element as userdata

Hierarchical Elements were pushed to Lua as plain tables. This is simple, but has the disadvantage that marshaling is eager: all child elements will be marshaled as part of the object. Using a Lua userdata object instead allows lazy access to fields, causing content marshaling just (but also each time) when a field is accessed. Filters which do not traverse the full element contents tree become faster as a result.

commitd126c26dd5f9eaed17462a3f1836b0edaf79e11c authorAlbert Krewinkel <albert@zeitkraut.de> dateSat 13 Oct 2018, 14:57 (8 years ago) parent3db9e15
1 file changed+24−19
src/Text/Pandoc/Lua/StackInstances.hs+24−19
src/Text/Pandoc/Lua/StackInstances.hs+24−19
@@ -36,9 +36,10 @@ module Text.Pandoc.Lua.StackInstances () where
3636
3737import Prelude
3838import Control.Applicative ((<|>))
39−import Control.Monad (when)
4039import Data.Data (showConstr, toConstr)
4140import Foreign.Lua (Lua, Peekable, Pushable, StackIndex)
41+import Foreign.Lua.Userdata ( ensureUserdataMetatable, pushAnyWithMetatable
42+ , metatableName)
4243import Text.Pandoc.Definition
4344import Text.Pandoc.Extensions (Extensions)
4445import Text.Pandoc.Lua.Util (defineHowTo, pushViaConstructor)
@@ -308,24 +309,28 @@ instance Peekable LuaListAttributes where
308309--
309310instance Pushable Element where
310311 push (Blk blk) = Lua.push blk
311− push (Sec lvl num attr label contents) = do
312− Lua.newtable
313− LuaUtil.addField "level" lvl
314− LuaUtil.addField "numbering" num
315− LuaUtil.addField "attr" (LuaAttr attr)
316− LuaUtil.addField "label" label
317− LuaUtil.addField "contents" contents
318− pushSecMetaTable
319− Lua.setmetatable (-2)
320− where
321− pushSecMetaTable :: Lua ()
322− pushSecMetaTable = do
323− inexistant <- Lua.newmetatable "PandocElementSec"
324− when inexistant $ do
325− LuaUtil.addField "t" "Sec"
326− Lua.push "__index"
327− Lua.pushvalue (-2)
328− Lua.rawset (-3)
312+ push sec = pushAnyWithMetatable pushElementMetatable sec
313+ where
314+ pushElementMetatable = ensureUserdataMetatable (metatableName sec) $
315+ LuaUtil.addFunction "__index" indexElement
316+
317+instance Peekable Element where
318+ peek idx = Lua.ltype idx >>= \case
319+ Lua.TypeUserdata -> Lua.peekAny idx
320+ _ -> Blk <$> Lua.peek idx
321+
322+indexElement :: Element -> String -> Lua Lua.NumResults
323+indexElement = \case
324+ (Blk _) -> const (1 <$ Lua.pushnil) -- this shouldn't happen
325+ (Sec lvl num attr label contents) -> fmap (return 1) . \case
326+ "level" -> Lua.push lvl
327+ "numbering" -> Lua.push num
328+ "attr" -> Lua.push (LuaAttr attr)
329+ "label" -> Lua.push label
330+ "contents" -> Lua.push contents
331+ "tag" -> Lua.push "Sec"
332+ "t" -> Lua.push "Sec"
333+ _ -> Lua.pushnil
329334
330335
331336--