#!/usr/bin/env python services = [] def service(name, iface, contractid): """Define a convenient service getter""" services.append((name, iface, contractid)) service('ChromeRegistryService', 'nsIChromeRegistry', "@mozilla.org/chrome/chrome-registry;1") service('ToolkitChromeRegistryService', 'nsIToolkitChromeRegistry', "@mozilla.org/chrome/chrome-registry;1") service('XULChromeRegistryService', 'nsIXULChromeRegistry', "@mozilla.org/chrome/chrome-registry;1") service('IOService', 'nsIIOService', "@mozilla.org/network/io-service;1") service('ObserverService', 'nsIObserverService', "@mozilla.org/observer-service;1") service('StringBundleService', 'nsIStringBundleService', "@mozilla.org/intl/stringbundle;1") service('PermissionManager', 'nsIPermissionManager', "@mozilla.org/permissionmanager;1") service('ServiceWorkerManager', 'nsIServiceWorkerManager', "@mozilla.org/serviceworkers/manager;1") service('AsyncShutdown', 'nsIAsyncShutdownService', "@mozilla.org/async-shutdown-service;1") service('UUIDGenerator', 'nsIUUIDGenerator', "@mozilla.org/uuid-generator;1") service('GfxInfo', 'nsIGfxInfo', "@mozilla.org/gfx/info;1") service('SocketTransportService', 'nsISocketTransportService', "@mozilla.org/network/socket-transport-service;1") service('StreamTransportService', 'nsIStreamTransportService', "@mozilla.org/network/stream-transport-service;1") service('CacheStorageService', 'nsICacheStorageService', "@mozilla.org/netwerk/cache-storage-service;1") service('URIClassifier', 'nsIURIClassifier', "@mozilla.org/uriclassifierservice") service('ActivityDistributor', 'nsIHttpActivityDistributor', "@mozilla.org/network/http-activity-distributor;1") service('HistoryService', 'mozilla::IHistory', "@mozilla.org/browser/history;1") service('ThirdPartyUtil', 'mozIThirdPartyUtil', "@mozilla.org/thirdpartyutil;1") service('URIFixup', 'nsIURIFixup', "@mozilla.org/docshell/urifixup;1") # The definition file needs access to the definitions of the particular # interfaces. If you add a new interface here, make sure the necessary includes # are also listed in the following code snippet. CPP_INCLUDES = """ #include "mozilla/Likely.h" #include "mozilla/Services.h" #include "mozIThirdPartyUtil.h" #include "nsComponentManager.h" #include "nsIObserverService.h" #include "nsNetCID.h" #include "nsObserverService.h" #include "nsXPCOMPrivate.h" #include "nsIIOService.h" #include "nsIDirectoryService.h" #include "nsIChromeRegistry.h" #include "nsIStringBundle.h" #include "nsIToolkitChromeRegistry.h" #include "IHistory.h" #include "nsIXPConnect.h" #include "nsIPermissionManager.h" #include "nsIServiceWorkerManager.h" #include "nsICacheStorageService.h" #include "nsIStreamTransportService.h" #include "nsISocketTransportService.h" #include "nsIURIClassifier.h" #include "nsIHttpActivityObserver.h" #include "nsIAsyncShutdown.h" #include "nsIUUIDGenerator.h" #include "nsIGfxInfo.h" #include "nsIURIFixup.h" """ ##### # Codegen Logic # # The following code consumes the data listed above to generate the files # Services.h, Services.cpp, and services.rs which provide access to these # service getters in both rust and C++ code. # # XXX(nika): would it be a good idea to unify Services.jsm into here too? def services_h(output): output.write("""\ /* THIS FILE IS GENERATED BY Services.py - DO NOT EDIT */ #ifndef mozilla_Services_h #define mozilla_Services_h #include "nscore.h" #include "nsCOMPtr.h" """) for (name, iface, contractid) in services: # Write out a forward declaration for the type in question segs = iface.split("::") for namespace in segs[:-1]: output.write("namespace %s {\n" % namespace) output.write("class %s;\n" % segs[-1]) for namespace in reversed(segs[:-1]): output.write("} // namespace %s\n" % namespace) # Write out the C-style function signature, and the C++ wrapper output.write(""" #ifdef MOZILLA_INTERNAL_API extern "C" { /** * NOTE: Don't call this method directly, instead call mozilla::services::Get{0}. * It is used to expose XPCOM services to rust code. The return value is already addrefed. */ %(type)s* XPCOMService_Get%(name)s(); } // extern "C" namespace mozilla { namespace services { /** * Fetch a cached instance of the %(name)s. * This function will return nullptr during XPCOM shutdown. */ inline already_AddRefed<%(type)s> Get%(name)s() { return already_AddRefed<%(type)s>(XPCOMService_Get%(name)s()); } } // namespace services } // namespace mozilla #endif // defined(MOZILLA_INTERNAL_API) """ % { 'name': name, 'type': iface, }) output.write("#endif // !defined(mozilla_Services_h)\n") def services_cpp(output): output.write("""\ /* THIS FILE IS GENERATED BY Services.py - DO NOT EDIT */ """) output.write(CPP_INCLUDES) for (name, iface, contractid) in services: output.write(""" static %(type)s* g%(name)s = nullptr; extern "C" { /** * NOTE: Don't call this method directly, instead call `mozilla::services::Get{0}`. * This method is extern "C" to expose XPCOM services to rust code. * The return value is already addrefed. */ %(type)s* XPCOMService_Get%(name)s() { if (MOZ_UNLIKELY(gXPCOMShuttingDown)) { return nullptr; } if (!g%(name)s) { nsCOMPtr<%(type)s> os = do_GetService("%(contractid)s"); os.swap(g%(name)s); } return do_AddRef(g%(name)s).take(); } } // extern "C" """ % { 'name': name, 'type': iface, 'contractid': contractid, }) output.write(""" /** * Clears service cache, sets gXPCOMShuttingDown */ void mozilla::services::Shutdown() { gXPCOMShuttingDown = true; """) for (name, iface, contractid) in services: output.write(" NS_IF_RELEASE(g%s);\n" % name) output.write("}\n") def services_rs(output): output.write("""\ /* THIS FILE IS GENERATED BY Services.py - DO NOT EDIT */ use RefPtr; """) for (name, iface, _) in services: # NOTE: We can't support namespaced interfaces in rust code, so we have to ignore them. if "::" in iface: continue output.write(""" /// Fetches a cached reference to the `%(name)s`. /// This function will return `None` during XPCOM shutdown. pub fn get_%(name)s() -> Option> { extern "C" { fn XPCOMService_Get%(name)s() -> *mut ::interfaces::%(type)s; } unsafe { RefPtr::from_raw_dont_addref(XPCOMService_Get%(name)s()) } } """ % { 'name': name, 'type': iface, })