diff -r 9d31581cc44e -r 810f66b468cd mercurial/policy.py --- a/mercurial/policy.py Thu Jun 13 23:28:31 2019 +0300 +++ b/mercurial/policy.py Wed May 29 13:27:56 2019 +0200 @@ -13,6 +13,9 @@ # Rules for how modules can be loaded. Values are: # # c - require C extensions +# rust+c - require Rust and C extensions +# rust+c-allow - allow Rust and C extensions with fallback to pure Python +# for each # allow - allow pure Python implementation when C loading fails # cffi - required cffi versions (implemented within pure module) # cffi-allow - allow pure Python implementation if cffi version is missing @@ -29,6 +32,9 @@ b'cffi': (r'cffi', None), b'cffi-allow': (r'cffi', r'pure'), b'py': (None, r'pure'), + # For now, rust policies impact importrust only + b'rust+c': (r'cext', None), + b'rust+c-allow': (r'cext', r'pure'), } try: @@ -107,3 +113,34 @@ raise pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname)) return _importfrom(pn, mn) + +def _isrustpermissive(): + """Assuming the policy is a Rust one, tell if it's permissive.""" + return policy.endswith(b'-allow') + +def importrust(modname, member=None, default=None): + """Import Rust module according to policy and availability. + + If policy isn't a Rust one, this returns `default`. + + If either the module or its member is not available, this returns `default` + if policy is permissive and raises `ImportError` if not. + """ + if not policy.startswith(b'rust'): + return default + + try: + mod = _importfrom(r'rustext', modname) + except ImportError: + if _isrustpermissive(): + return default + raise + if member is None: + return mod + + try: + return getattr(mod, member) + except AttributeError: + if _isrustpermissive(): + return default + raise ImportError(r"Cannot import name %s" % member)