##// END OF EJS Templates
rust: exposing in parsers module...
Georges Racinet -
r40309:3b275f54 default
parent child Browse files
Show More
@@ -2290,6 +2290,152 b' bail:'
2290 2290 return NULL;
2291 2291 }
2292 2292
2293 #ifdef WITH_RUST
2294
2295 /* rustlazyancestors: iteration over ancestors implemented in Rust
2296 *
2297 * This class holds a reference to an index and to the Rust iterator.
2298 */
2299 typedef struct rustlazyancestorsObjectStruct rustlazyancestorsObject;
2300
2301 struct rustlazyancestorsObjectStruct {
2302 PyObject_HEAD
2303 /* Type-specific fields go here. */
2304 indexObject *index; /* Ref kept to avoid GC'ing the index */
2305 void *iter; /* Rust iterator */
2306 };
2307
2308 /* FFI exposed from Rust code */
2309 rustlazyancestorsObject *rustlazyancestors_init(
2310 indexObject *index,
2311 /* to pass index_get_parents() */
2312 int (*)(indexObject *, Py_ssize_t, int*, int),
2313 /* intrevs vector */
2314 int initrevslen, long *initrevs,
2315 long stoprev,
2316 int inclusive);
2317 void rustlazyancestors_drop(rustlazyancestorsObject *self);
2318 int rustlazyancestors_next(rustlazyancestorsObject *self);
2319
2320 /* CPython instance methods */
2321 static int rustla_init(rustlazyancestorsObject *self,
2322 PyObject *args) {
2323 PyObject *initrevsarg = NULL;
2324 PyObject *inclusivearg = NULL;
2325 long stoprev = 0;
2326 long *initrevs = NULL;
2327 int inclusive = 0;
2328 Py_ssize_t i;
2329
2330 indexObject *index;
2331 if (!PyArg_ParseTuple(args, "O!O!lO!",
2332 &indexType, &index,
2333 &PyList_Type, &initrevsarg,
2334 &stoprev,
2335 &PyBool_Type, &inclusivearg))
2336 return -1;
2337
2338 Py_INCREF(index);
2339 self->index = index;
2340
2341 if (inclusivearg == Py_True)
2342 inclusive = 1;
2343
2344 Py_ssize_t linit = PyList_GET_SIZE(initrevsarg);
2345
2346 initrevs = (long*)calloc(linit, sizeof(long));
2347
2348 if (initrevs == NULL) {
2349 PyErr_NoMemory();
2350 goto bail;
2351 }
2352
2353 for (i=0; i<linit; i++) {
2354 initrevs[i] = PyInt_AsLong(PyList_GET_ITEM(initrevsarg, i));
2355 }
2356 if (PyErr_Occurred())
2357 goto bail;
2358
2359 self->iter = rustlazyancestors_init(index,
2360 index_get_parents,
2361 linit, initrevs,
2362 stoprev, inclusive);
2363 if (self->iter == NULL) {
2364 /* if this is because of GraphError::ParentOutOfRange
2365 * index_get_parents() has already set the proper ValueError */
2366 goto bail;
2367 }
2368
2369 free(initrevs);
2370 return 0;
2371
2372 bail:
2373 free(initrevs);
2374 return -1;
2375 };
2376
2377 static void rustla_dealloc(rustlazyancestorsObject *self)
2378 {
2379 Py_XDECREF(self->index);
2380 if (self->iter != NULL) { /* can happen if rustla_init failed */
2381 rustlazyancestors_drop(self->iter);
2382 }
2383 PyObject_Del(self);
2384 }
2385
2386 static PyObject *rustla_next(rustlazyancestorsObject *self) {
2387 int res = rustlazyancestors_next(self->iter);
2388 if (res == -1) {
2389 /* Setting an explicit exception seems unnecessary
2390 * as examples from Python source code (Objects/rangeobjets.c and
2391 * Modules/_io/stringio.c) seem to demonstrate.
2392 */
2393 return NULL;
2394 }
2395 return PyInt_FromLong(res);
2396 }
2397
2398 static PyTypeObject rustlazyancestorsType = {
2399 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2400 "parsers.rustlazyancestors", /* tp_name */
2401 sizeof(rustlazyancestorsObject), /* tp_basicsize */
2402 0, /* tp_itemsize */
2403 (destructor)rustla_dealloc, /* tp_dealloc */
2404 0, /* tp_print */
2405 0, /* tp_getattr */
2406 0, /* tp_setattr */
2407 0, /* tp_compare */
2408 0, /* tp_repr */
2409 0, /* tp_as_number */
2410 0, /* tp_as_sequence */
2411 0, /* tp_as_mapping */
2412 0, /* tp_hash */
2413 0, /* tp_call */
2414 0, /* tp_str */
2415 0, /* tp_getattro */
2416 0, /* tp_setattro */
2417 0, /* tp_as_buffer */
2418 Py_TPFLAGS_DEFAULT, /* tp_flags */
2419 "Iterator over ancestors, implemented in Rust", /* tp_doc */
2420 0, /* tp_traverse */
2421 0, /* tp_clear */
2422 0, /* tp_richcompare */
2423 0, /* tp_weaklistoffset */
2424 0, /* tp_iter */
2425 (iternextfunc)rustla_next, /* tp_iternext */
2426 0, /* tp_methods */
2427 0, /* tp_members */
2428 0, /* tp_getset */
2429 0, /* tp_base */
2430 0, /* tp_dict */
2431 0, /* tp_descr_get */
2432 0, /* tp_descr_set */
2433 0, /* tp_dictoffset */
2434 (initproc)rustla_init, /* tp_init */
2435 0, /* tp_alloc */
2436 };
2437 #endif /* WITH_RUST */
2438
2293 2439 void revlog_module_init(PyObject *mod)
2294 2440 {
2295 2441 indexType.tp_new = PyType_GenericNew;
@@ -2310,4 +2456,14 b' void revlog_module_init(PyObject *mod)'
2310 2456 }
2311 2457 if (nullentry)
2312 2458 PyObject_GC_UnTrack(nullentry);
2459
2460 #ifdef WITH_RUST
2461 rustlazyancestorsType.tp_new = PyType_GenericNew;
2462 if (PyType_Ready(&rustlazyancestorsType) < 0)
2463 return;
2464 Py_INCREF(&rustlazyancestorsType);
2465 PyModule_AddObject(mod, "rustlazyancestors",
2466 (PyObject *)&rustlazyancestorsType);
2467 #endif
2468
2313 2469 }
@@ -132,6 +132,8 b' else:'
132 132
133 133 ispypy = "PyPy" in sys.version
134 134
135 iswithrustextensions = 'HGWITHRUSTEXT' in os.environ
136
135 137 import ctypes
136 138 import stat, subprocess, time
137 139 import re
@@ -460,6 +462,8 b' class hgbuildext(build_ext):'
460 462 return build_ext.build_extensions(self)
461 463
462 464 def build_extension(self, ext):
465 if isinstance(ext, RustExtension):
466 ext.rustbuild()
463 467 try:
464 468 build_ext.build_extension(self, ext)
465 469 except CCompilerError:
@@ -884,6 +888,54 b' xdiff_headers = ['
884 888 'mercurial/thirdparty/xdiff/xutils.h',
885 889 ]
886 890
891 class RustExtension(Extension):
892 """A C Extension, conditionnally enhanced with Rust code.
893
894 if iswithrustextensions is False, does nothing else than plain Extension
895 """
896
897 rusttargetdir = os.path.join('rust', 'target', 'release')
898
899 def __init__(self, mpath, sources, rustlibname, subcrate, **kw):
900 Extension.__init__(self, mpath, sources, **kw)
901 if not iswithrustextensions:
902 return
903 srcdir = self.rustsrcdir = os.path.join('rust', subcrate)
904 self.libraries.append(rustlibname)
905 self.extra_compile_args.append('-DWITH_RUST')
906
907 # adding Rust source and control files to depends so that the extension
908 # gets rebuilt if they've changed
909 self.depends.append(os.path.join(srcdir, 'Cargo.toml'))
910 cargo_lock = os.path.join(srcdir, 'Cargo.lock')
911 if os.path.exists(cargo_lock):
912 self.depends.append(cargo_lock)
913 for dirpath, subdir, fnames in os.walk(os.path.join(srcdir, 'src')):
914 self.depends.extend(os.path.join(dirpath, fname)
915 for fname in fnames
916 if os.path.splitext(fname)[1] == '.rs')
917
918 def rustbuild(self):
919 if not iswithrustextensions:
920 return
921 env = os.environ.copy()
922 if 'HGTEST_RESTOREENV' in env:
923 # Mercurial tests change HOME to a temporary directory,
924 # but, if installed with rustup, the Rust toolchain needs
925 # HOME to be correct (otherwise the 'no default toolchain'
926 # error message is issued and the build fails).
927 # This happens currently with test-hghave.t, which does
928 # invoke this build.
929
930 # Unix only fix (os.path.expanduser not really reliable if
931 # HOME is shadowed like this)
932 import pwd
933 env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir
934
935 subprocess.check_call(['cargo', 'build', '-vv', '--release'],
936 env=env, cwd=self.rustsrcdir)
937 self.library_dirs.append(self.rusttargetdir)
938
887 939 extmodules = [
888 940 Extension('mercurial.cext.base85', ['mercurial/cext/base85.c'],
889 941 include_dirs=common_include_dirs,
@@ -896,14 +948,19 b' extmodules = ['
896 948 'mercurial/cext/mpatch.c'],
897 949 include_dirs=common_include_dirs,
898 950 depends=common_depends),
899 Extension('mercurial.cext.parsers', ['mercurial/cext/charencode.c',
900 'mercurial/cext/dirs.c',
901 'mercurial/cext/manifest.c',
902 'mercurial/cext/parsers.c',
903 'mercurial/cext/pathencode.c',
904 'mercurial/cext/revlog.c'],
905 include_dirs=common_include_dirs,
906 depends=common_depends + ['mercurial/cext/charencode.h']),
951 RustExtension('mercurial.cext.parsers', ['mercurial/cext/charencode.c',
952 'mercurial/cext/dirs.c',
953 'mercurial/cext/manifest.c',
954 'mercurial/cext/parsers.c',
955 'mercurial/cext/pathencode.c',
956 'mercurial/cext/revlog.c'],
957 'hgdirectffi',
958 'hg-direct-ffi',
959 include_dirs=common_include_dirs,
960 depends=common_depends + ['mercurial/cext/charencode.h',
961 'mercurial/rust/src/lib.rs',
962 'mercurial/rust/src/ancestors.rs',
963 'mercurial/rust/src/cpython.rs']),
907 964 Extension('mercurial.cext.osutil', ['mercurial/cext/osutil.c'],
908 965 include_dirs=common_include_dirs,
909 966 extra_compile_args=osutil_cflags,
General Comments 0
You need to be logged in to leave comments. Login now