Guest User

namespace.lua

a guest
Jun 21st, 2015
262
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ------------------------------------------------------------------------------
  2. --
  3. -- LGI Support for repository namespace
  4. --
  5. -- Copyright (c) 2010, 2011 Pavel Holejsovsky
  6. -- Licensed under the MIT license:
  7. -- http://www.opensource.org/licenses/mit-license.php
  8. --
  9. ------------------------------------------------------------------------------
  10.  
  11. local type, rawget, next, pairs, require, pcall, setmetatable, assert
  12. = type, rawget, next, pairs, require, pcall, setmetatable, assert
  13. local package = require 'package'
  14. local core = require 'lgi.core'
  15. local enum = require 'lgi.enum'
  16. local component = require 'lgi.component'
  17. local record = require 'lgi.record'
  18. local class = require 'lgi.class'
  19.  
  20. -- Table containing loaders for various GI types, indexed by
  21. -- gi.InfoType constants.
  22. local typeloader = {}
  23.  
  24. typeloader['function'] =
  25. function(namespace, info)
  26. return core.callable.new(info), '_function'
  27. end
  28.  
  29. function typeloader.constant(namespace, info)
  30. return core.constant(info), '_constant'
  31. end
  32.  
  33. function typeloader.enum(namespace, info)
  34. return enum.load(info, enum.enum_mt), '_enum'
  35. end
  36.  
  37. function typeloader.flags(namespace, info)
  38. return enum.load(info, enum.bitflags_mt), '_enum'
  39. end
  40.  
  41. function typeloader.struct(namespace, info)
  42. -- Avoid exposing internal structs created for object implementations.
  43. if not info.is_gtype_struct then
  44. return record.load(info), '_struct'
  45. end
  46. end
  47.  
  48. function typeloader.union(namespace, info)
  49. return record.load(info), '_union'
  50. end
  51.  
  52. function typeloader.interface(namespace, info)
  53. return class.load_interface(namespace, info), '_interface'
  54. end
  55.  
  56. function typeloader.object(namespace, info)
  57. return class.load_class(namespace, info), '_class'
  58. end
  59.  
  60. -- Repo namespace metatable.
  61. local namespace = {
  62. mt = {
  63. _categories = { '_class', '_interface', '_struct', '_union', '_enum',
  64. '_function', '_constant', } }
  65. }
  66.  
  67. -- Gets symbol of the specified namespace, if not present yet, tries to load it
  68. -- on-demand.
  69. function namespace.mt:__index(symbol)
  70. -- Check whether symbol is present in the metatable.
  71. local val = namespace.mt[symbol]
  72. if val then return val end
  73.  
  74. -- Check, whether there is some precondition in the lazy-loading table.
  75. local preconditions = rawget(self, '_precondition')
  76. local precondition = preconditions and preconditions[symbol]
  77. if precondition then
  78. local package = preconditions[symbol]
  79. if not preconditions[package] then
  80. preconditions[package] = true
  81. require('lgi.override.' .. package)
  82. preconditions[package] = nil
  83. end
  84. preconditions[symbol] = nil
  85. if not next(preconditions) then self._precondition = nil end
  86. end
  87.  
  88. -- Check, whether symbol is already loaded.
  89. val = component.mt._element(self, nil, symbol, namespace.mt._categories)
  90. if val then return val end
  91.  
  92. -- Lookup baseinfo of requested symbol in the GIRepository.
  93. local info = core.gi[self._name][symbol]
  94. if not info then return nil end
  95.  
  96. -- Decide according to symbol type what to do.
  97. local loader = typeloader[info.type]
  98. if loader then
  99. local category
  100. val, category = loader(self, info)
  101.  
  102. -- Cache the symbol in specified category in the namespace.
  103. if val then
  104. local cat = rawget(self, category)
  105. if not cat then
  106. cat = {}
  107. self[category] = cat
  108. end
  109. -- Store symbol into the repo, but only if it is not already
  110. -- there. It could by added to repo as byproduct of loading
  111. -- other symbol.
  112. if not cat[symbol] then cat[symbol] = val end
  113. elseif info.is_gtype_struct then
  114. -- If we have XxxClass name, try to lookup class structure of
  115. -- the Xxx object.
  116. local class = (symbol:match('^(%w+)Class$')
  117. or symbol:match('^(%w+)Iface$')
  118. or symbol:match('^(%w+)Interface$'))
  119. if class then
  120. class = self[class]
  121. if class then val = class._class end
  122. end
  123. end
  124. end
  125. return val
  126. end
  127.  
  128. -- Resolves everything in the namespace by iterating through it.
  129. function namespace.mt:_resolve(recurse)
  130. -- Iterate through all items in the namespace and dereference them,
  131. -- which causes them to be loaded in and cached inside the namespace
  132. -- table.
  133. local gi_ns = core.gi[self._name]
  134. for i = 1, #gi_ns do
  135. local ok, component = pcall(function() return self[gi_ns[i].name] end)
  136. if ok and recurse and type(component) == 'table' then
  137. local resolve = component._resolve
  138. if resolve then resolve(component, recurse) end
  139. end
  140. end
  141. return self
  142. end
  143.  
  144. -- Makes sure that the namespace (optionally with requested version)
  145. -- is properly loaded.
  146. function namespace.require(name, version)
  147. -- Load the namespace info for GIRepository. This also verifies
  148. -- whether requested version can be loaded.
  149. local ns_info = assert(core.gi.require(name, version))
  150.  
  151. -- If the repository table does not exist yet, create it.
  152. local ns = rawget(core.repo, name)
  153. if not ns then
  154. ns = setmetatable({ _name = name, _version = ns_info.version,
  155. _dependencies = ns_info.dependencies },
  156. namespace.mt)
  157. core.repo[name] = ns
  158.  
  159. -- Make sure that all dependent namespaces are also loaded.
  160. for name, version in pairs(ns._dependencies or {}) do
  161. namespace.require(name, version)
  162. end
  163.  
  164. -- Try to load override, if it is present.
  165. local override_name = 'lgi.override.' .. ns._name
  166. local ok, msg = pcall(require, override_name)
  167. if not ok then
  168. -- Try parsing message; if it is something different than
  169. -- "module xxx not found", then attempt to load again and let
  170. -- the exception fly out.
  171. if not msg:find("module '" .. override_name .. "' not found:",
  172. 1, true) then
  173. package.loaded[override_name] = nil
  174. require(override_name)
  175. end
  176. end
  177. end
  178. return ns
  179. end
  180.  
  181. return namespace
RAW Paste Data