Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion pyo3-polars/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ description = "Expression plugins and PyO3 types for polars"

[dependencies]
ciborium = { version = "0.2.1", optional = true }
polars = { workspace = true, default-features = false }
polars-core = { workspace = true, default-features = false }
polars-ffi = { workspace = true, optional = true }
polars-lazy = { workspace = true, optional = true }
Expand All @@ -21,6 +20,12 @@ pyo3-polars-derive = { version = "0.5.0", path = "../pyo3-polars-derive", option
serde = { version = "1", optional = true }
serde-pickle = { version = "1", optional = true }
thiserror = "1"
once_cell = "1"
itoa = "1.0.6"

[dependencies.polars]
workspace = true
features = ["dtype-full"]

[features]
lazy = ["polars/serde-lazy", "polars-plan", "polars-lazy/serde", "ciborium"]
Expand Down
34 changes: 34 additions & 0 deletions pyo3-polars/src/gil_once_cell.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use std::cell::UnsafeCell;

use pyo3::{PyResult, Python};

// Adapted from PYO3 with the only change that
// we allow mutable access with when the GIL is held

pub struct GILOnceCell<T>(UnsafeCell<Option<T>>);

// T: Send is needed for Sync because the thread which drops the GILOnceCell can be different
// to the thread which fills it.
unsafe impl<T: Send + Sync> Sync for GILOnceCell<T> {}
unsafe impl<T: Send> Send for GILOnceCell<T> {}

impl<T> GILOnceCell<T> {
Copy link
Author

@JabobKrauskopf JabobKrauskopf Mar 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation of the GILOnceCell can only be used if the users of this library also include a function that is called "on startup", that initializes the value in the Cell, similar to https://github.com/pola-rs/polars/blob/97eff077f37209386836361e9ab4da582bc5b18e/py-polars/src/on_startup.rs#L98

I don't think that this requirement would be a good idea. We could check in the with_gil function if the value in the cell has been initialized, and if not initialize it there

/// Create a `GILOnceCell` which does not yet contain a value.
pub const fn new() -> Self {
Self(UnsafeCell::new(None))
}

/// as long as we have the GIL we can mutate
/// this creates a context that checks that.
pub fn with_gil<F, O>(&self, _py: Python<'_>, mut op: F) -> PyResult<O>
where
F: FnMut(&mut T) -> PyResult<O>,
{
// Safe because GIL is held, so no other thread can be writing to this cell concurrently.
let inner = unsafe { &mut *self.0.get() }
.as_mut()
.expect("not yet initialized");

op(inner)
}
}
Loading