Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement FromPyObject and IntoPy Traits for AnyValue #37

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
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