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