312 self.cindex(py).borrow().inner().getattr(py, "rust_ext_compat")?.extract::<PyInt>(py) |
312 self.cindex(py).borrow().inner().getattr(py, "rust_ext_compat")?.extract::<PyInt>(py) |
313 } |
313 } |
314 |
314 |
315 }); |
315 }); |
316 |
316 |
|
317 /// Take a (potentially) mmap'ed buffer, and return the underlying Python |
|
318 /// buffer along with the Rust slice into said buffer. We need to keep the |
|
319 /// Python buffer around, otherwise we'd get a dangling pointer once the buffer |
|
320 /// is freed from Python's side. |
|
321 /// |
|
322 /// # Safety |
|
323 /// |
|
324 /// The caller must make sure that the buffer is kept around for at least as |
|
325 /// long as the slice. |
|
326 #[deny(unsafe_op_in_unsafe_fn)] |
|
327 unsafe fn mmap_keeparound( |
|
328 py: Python, |
|
329 data: PyObject, |
|
330 ) -> PyResult<( |
|
331 PyBuffer, |
|
332 Box<dyn std::ops::Deref<Target = [u8]> + Send + 'static>, |
|
333 )> { |
|
334 let buf = PyBuffer::get(py, &data)?; |
|
335 let len = buf.item_count(); |
|
336 |
|
337 // Build a slice from the mmap'ed buffer data |
|
338 let cbuf = buf.buf_ptr(); |
|
339 let bytes = if std::mem::size_of::<u8>() == buf.item_size() |
|
340 && buf.is_c_contiguous() |
|
341 && u8::is_compatible_format(buf.format()) |
|
342 { |
|
343 unsafe { std::slice::from_raw_parts(cbuf as *const u8, len) } |
|
344 } else { |
|
345 return Err(PyErr::new::<ValueError, _>( |
|
346 py, |
|
347 "Nodemap data buffer has an invalid memory representation" |
|
348 .to_string(), |
|
349 )); |
|
350 }; |
|
351 |
|
352 Ok((buf, Box::new(bytes))) |
|
353 } |
|
354 |
317 impl MixedIndex { |
355 impl MixedIndex { |
318 fn new(py: Python, cindex: PyObject) -> PyResult<MixedIndex> { |
356 fn new(py: Python, cindex: PyObject) -> PyResult<MixedIndex> { |
319 Self::create_instance( |
357 Self::create_instance( |
320 py, |
358 py, |
321 RefCell::new(cindex::Index::new(py, cindex)?), |
359 RefCell::new(cindex::Index::new(py, cindex)?), |
425 &self, |
463 &self, |
426 py: Python, |
464 py: Python, |
427 docket: PyObject, |
465 docket: PyObject, |
428 nm_data: PyObject, |
466 nm_data: PyObject, |
429 ) -> PyResult<PyObject> { |
467 ) -> PyResult<PyObject> { |
430 let buf = PyBuffer::get(py, &nm_data)?; |
468 // Safety: we keep the buffer around inside the class as `nodemap_mmap` |
|
469 let (buf, bytes) = unsafe { mmap_keeparound(py, nm_data)? }; |
431 let len = buf.item_count(); |
470 let len = buf.item_count(); |
432 |
|
433 // Build a slice from the mmap'ed buffer data |
|
434 let cbuf = buf.buf_ptr(); |
|
435 let bytes = if std::mem::size_of::<u8>() == buf.item_size() |
|
436 && buf.is_c_contiguous() |
|
437 && u8::is_compatible_format(buf.format()) |
|
438 { |
|
439 unsafe { std::slice::from_raw_parts(cbuf as *const u8, len) } |
|
440 } else { |
|
441 return Err(PyErr::new::<ValueError, _>( |
|
442 py, |
|
443 "Nodemap data buffer has an invalid memory representation" |
|
444 .to_string(), |
|
445 )); |
|
446 }; |
|
447 |
|
448 // Keep a reference to the mmap'ed buffer, otherwise we get a dangling |
|
449 // pointer. |
|
450 self.nodemap_mmap(py).borrow_mut().replace(buf); |
471 self.nodemap_mmap(py).borrow_mut().replace(buf); |
451 |
472 |
452 let mut nt = NodeTree::load_bytes(Box::new(bytes), len); |
473 let mut nt = NodeTree::load_bytes(bytes, len); |
453 |
474 |
454 let data_tip = docket |
475 let data_tip = docket |
455 .getattr(py, "tip_rev")? |
476 .getattr(py, "tip_rev")? |
456 .extract::<BaseRevision>(py)? |
477 .extract::<BaseRevision>(py)? |
457 .into(); |
478 .into(); |