use std::mem::ManuallyDrop;
use super::*;
use crate::prelude::*;
pub struct PolarsExtension {
array: Option<FixedSizeBinaryArray>,
}
impl PolarsExtension {
pub(crate) unsafe fn new(array: FixedSizeBinaryArray) -> Self {
Self { array: Some(array) }
}
pub(crate) fn take_and_forget(self) -> FixedSizeBinaryArray {
let mut md = ManuallyDrop::new(self);
md.array.take().unwrap()
}
unsafe fn with_sentinel<T, F: FnOnce(&mut ExtensionSentinel) -> T>(&self, fun: F) -> T {
let mut sentinel = self.get_sentinel();
let out = fun(&mut sentinel);
std::mem::forget(sentinel);
out
}
unsafe fn get_sentinel(&self) -> Box<ExtensionSentinel> {
if let ArrowDataType::Extension(ext) = self.array.as_ref().unwrap().dtype() {
let metadata = ext
.metadata
.as_ref()
.expect("should have metadata in extension type");
let mut iter = metadata.split(';');
let pid = iter.next().unwrap().parse::<u128>().unwrap();
let ptr = iter.next().unwrap().parse::<usize>().unwrap();
if pid == *PROCESS_ID {
Box::from_raw(ptr as *const ExtensionSentinel as *mut ExtensionSentinel)
} else {
panic!("pid did not mach process id")
}
} else {
panic!("should be extension type")
}
}
pub(crate) unsafe fn get_series(&self, name: &PlSmallStr) -> Series {
self.with_sentinel(|sent| {
(sent.to_series_fn.as_ref().unwrap())(self.array.as_ref().unwrap(), name)
})
}
pub(crate) unsafe fn set_to_series_fn<T: PolarsObject>(&mut self) {
let f = Box::new(move |arr: &FixedSizeBinaryArray, name: &PlSmallStr| {
let iter = arr.iter().map(|opt| {
opt.map(|bytes| {
let t = std::ptr::read_unaligned(bytes.as_ptr() as *const T);
let ret = t.clone();
std::mem::forget(t);
ret
})
});
let ca = ObjectChunked::<T>::from_iter_options(name.clone(), iter);
ca.into_series()
});
self.with_sentinel(move |sent| {
sent.to_series_fn = Some(f);
});
}
}
impl Drop for PolarsExtension {
fn drop(&mut self) {
unsafe { self.get_sentinel() };
}
}