xpcom/build/Services.py
author Boris Zbarsky <bzbarsky@mit.edu>
Tue, 29 May 2018 22:58:49 -0400
changeset 477120 e46b5b3027713125c2e472c3d1d9dc0ba8a3387a
parent 455579 dc16d00a1e4ddebbdc258ae5f4d6700c04a71794
child 478265 60441ab73a45d36b987c8792842253567bd15d35
permissions -rw-r--r--
Bug 1455676 part 14. Remove most use of nsIDOMNode in dom/. r=qdot

#!/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('XULOverlayProviderService', 'nsIXULOverlayProvider',
        "@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('XPConnect', 'nsIXPConnect',
        "@mozilla.org/js/xpc/XPConnect;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")

# 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 "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 "nsIXULOverlayProvider.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"
"""

#####
# 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<RefPtr<::interfaces::%(type)s>> {
    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,
})