Show More
@@ -2290,6 +2290,152 b' bail:' | |||||
2290 | return NULL; |
|
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 | void revlog_module_init(PyObject *mod) |
|
2439 | void revlog_module_init(PyObject *mod) | |
2294 | { |
|
2440 | { | |
2295 | indexType.tp_new = PyType_GenericNew; |
|
2441 | indexType.tp_new = PyType_GenericNew; | |
@@ -2310,4 +2456,14 b' void revlog_module_init(PyObject *mod)' | |||||
2310 | } |
|
2456 | } | |
2311 | if (nullentry) |
|
2457 | if (nullentry) | |
2312 | PyObject_GC_UnTrack(nullentry); |
|
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 | ispypy = "PyPy" in sys.version |
|
133 | ispypy = "PyPy" in sys.version | |
134 |
|
134 | |||
|
135 | iswithrustextensions = 'HGWITHRUSTEXT' in os.environ | |||
|
136 | ||||
135 | import ctypes |
|
137 | import ctypes | |
136 | import stat, subprocess, time |
|
138 | import stat, subprocess, time | |
137 | import re |
|
139 | import re | |
@@ -460,6 +462,8 b' class hgbuildext(build_ext):' | |||||
460 | return build_ext.build_extensions(self) |
|
462 | return build_ext.build_extensions(self) | |
461 |
|
463 | |||
462 | def build_extension(self, ext): |
|
464 | def build_extension(self, ext): | |
|
465 | if isinstance(ext, RustExtension): | |||
|
466 | ext.rustbuild() | |||
463 | try: |
|
467 | try: | |
464 | build_ext.build_extension(self, ext) |
|
468 | build_ext.build_extension(self, ext) | |
465 | except CCompilerError: |
|
469 | except CCompilerError: | |
@@ -884,6 +888,54 b' xdiff_headers = [' | |||||
884 | 'mercurial/thirdparty/xdiff/xutils.h', |
|
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 | extmodules = [ |
|
939 | extmodules = [ | |
888 | Extension('mercurial.cext.base85', ['mercurial/cext/base85.c'], |
|
940 | Extension('mercurial.cext.base85', ['mercurial/cext/base85.c'], | |
889 | include_dirs=common_include_dirs, |
|
941 | include_dirs=common_include_dirs, | |
@@ -896,14 +948,19 b' extmodules = [' | |||||
896 | 'mercurial/cext/mpatch.c'], |
|
948 | 'mercurial/cext/mpatch.c'], | |
897 | include_dirs=common_include_dirs, |
|
949 | include_dirs=common_include_dirs, | |
898 | depends=common_depends), |
|
950 | depends=common_depends), | |
899 | Extension('mercurial.cext.parsers', ['mercurial/cext/charencode.c', |
|
951 | RustExtension('mercurial.cext.parsers', ['mercurial/cext/charencode.c', | |
900 | 'mercurial/cext/dirs.c', |
|
952 | 'mercurial/cext/dirs.c', | |
901 | 'mercurial/cext/manifest.c', |
|
953 | 'mercurial/cext/manifest.c', | |
902 | 'mercurial/cext/parsers.c', |
|
954 | 'mercurial/cext/parsers.c', | |
903 | 'mercurial/cext/pathencode.c', |
|
955 | 'mercurial/cext/pathencode.c', | |
904 | 'mercurial/cext/revlog.c'], |
|
956 | 'mercurial/cext/revlog.c'], | |
905 | include_dirs=common_include_dirs, |
|
957 | 'hgdirectffi', | |
906 | depends=common_depends + ['mercurial/cext/charencode.h']), |
|
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 | Extension('mercurial.cext.osutil', ['mercurial/cext/osutil.c'], |
|
964 | Extension('mercurial.cext.osutil', ['mercurial/cext/osutil.c'], | |
908 | include_dirs=common_include_dirs, |
|
965 | include_dirs=common_include_dirs, | |
909 | extra_compile_args=osutil_cflags, |
|
966 | extra_compile_args=osutil_cflags, |
General Comments 0
You need to be logged in to leave comments.
Login now