polars_core/chunked_array/object/
registry.rs1use std::any::Any;
6use std::fmt::{Debug, Formatter};
7use std::ops::Deref;
8use std::sync::{Arc, LazyLock, RwLock};
9
10use arrow::array::builder::ArrayBuilder;
11use arrow::array::{Array, ArrayRef};
12use arrow::datatypes::ArrowDataType;
13use polars_utils::pl_str::PlSmallStr;
14
15use crate::chunked_array::object::builder::ObjectChunkedBuilder;
16use crate::datatypes::AnyValue;
17use crate::prelude::{ListBuilderTrait, ObjectChunked, PolarsObject};
18use crate::series::{IntoSeries, Series};
19
20pub type BuilderConstructor =
22 Box<dyn Fn(PlSmallStr, usize) -> Box<dyn AnonymousObjectBuilder> + Send + Sync>;
23pub type ObjectConverter = Arc<dyn Fn(AnyValue) -> Box<dyn Any> + Send + Sync>;
24pub type PyObjectConverter = Arc<dyn Fn(AnyValue) -> Box<dyn Any> + Send + Sync>;
25pub type ObjectArrayGetter = Arc<dyn Fn(&dyn Array, usize) -> Option<AnyValue<'_>> + Send + Sync>;
26pub type WithGIL = Arc<dyn Fn(&mut dyn FnMut()) + Send + Sync>;
27
28pub struct ObjectRegistry {
29 pub builder_constructor: BuilderConstructor,
31 object_converter: Option<ObjectConverter>,
33 pyobject_converter: Option<PyObjectConverter>,
35 pub physical_dtype: ArrowDataType,
36 array_getter: ObjectArrayGetter,
38 with_gil: WithGIL,
40}
41
42impl Debug for ObjectRegistry {
43 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
44 write!(f, "object-registry")
45 }
46}
47
48static GLOBAL_OBJECT_REGISTRY: LazyLock<RwLock<Option<ObjectRegistry>>> =
49 LazyLock::new(Default::default);
50
51pub trait AnonymousObjectBuilder: ArrayBuilder {
54 fn as_array_builder(self: Box<Self>) -> Box<dyn ArrayBuilder>;
55
56 unsafe fn from_chunks(self: Box<Self>, chunks: Vec<ArrayRef>) -> Series;
59
60 fn append_null(&mut self);
62
63 fn append_value(&mut self, value: &dyn Any);
67
68 #[inline]
69 fn append_option(&mut self, value: Option<&dyn Any>) {
70 match value {
71 None => self.append_null(),
72 Some(v) => self.append_value(v),
73 }
74 }
75
76 fn to_series(&mut self) -> Series;
79
80 fn get_list_builder(
81 &self,
82 name: PlSmallStr,
83 values_capacity: usize,
84 list_capacity: usize,
85 ) -> Box<dyn ListBuilderTrait>;
86}
87
88impl<T: PolarsObject> AnonymousObjectBuilder for ObjectChunkedBuilder<T> {
89 unsafe fn from_chunks(self: Box<Self>, chunks: Vec<ArrayRef>) -> Series {
92 ObjectChunked::<T>::new_with_compute_len(Arc::new(self.field().clone()), chunks)
93 .into_series()
94 }
95
96 fn as_array_builder(self: Box<Self>) -> Box<dyn ArrayBuilder> {
97 self
98 }
99
100 fn append_null(&mut self) {
101 self.append_null()
102 }
103
104 fn append_value(&mut self, value: &dyn Any) {
105 let value = value.downcast_ref::<T>().unwrap();
106 self.append_value(value.clone())
107 }
108
109 fn to_series(&mut self) -> Series {
110 let builder = std::mem::take(self);
111 builder.finish().into_series()
112 }
113 fn get_list_builder(
114 &self,
115 name: PlSmallStr,
116 values_capacity: usize,
117 list_capacity: usize,
118 ) -> Box<dyn ListBuilderTrait> {
119 Box::new(super::extension::list::ExtensionListBuilder::<T>::new(
120 name,
121 values_capacity,
122 list_capacity,
123 ))
124 }
125}
126
127pub fn register_object_builder(
128 builder_constructor: BuilderConstructor,
129 object_converter: ObjectConverter,
130 pyobject_converter: PyObjectConverter,
131 physical_dtype: ArrowDataType,
132 array_getter: ObjectArrayGetter,
133 with_gil: WithGIL,
134) {
135 let reg = GLOBAL_OBJECT_REGISTRY.deref();
136 let mut reg = reg.write().unwrap();
137
138 *reg = Some(ObjectRegistry {
139 builder_constructor,
140 object_converter: Some(object_converter),
141 pyobject_converter: Some(pyobject_converter),
142 physical_dtype,
143 array_getter,
144 with_gil,
145 })
146}
147
148#[cold]
149pub fn get_object_physical_type() -> ArrowDataType {
150 let reg = GLOBAL_OBJECT_REGISTRY.read().unwrap();
151 let reg = reg.as_ref().unwrap();
152 reg.physical_dtype.clone()
153}
154
155pub fn get_object_builder(name: PlSmallStr, capacity: usize) -> Box<dyn AnonymousObjectBuilder> {
156 let reg = GLOBAL_OBJECT_REGISTRY.read().unwrap();
157 let reg = reg.as_ref().unwrap();
158 (reg.builder_constructor)(name, capacity)
159}
160
161pub fn get_object_converter() -> ObjectConverter {
162 let reg = GLOBAL_OBJECT_REGISTRY.read().unwrap();
163 let reg = reg.as_ref().unwrap();
164 reg.object_converter.as_ref().unwrap().clone()
165}
166
167pub fn get_pyobject_converter() -> PyObjectConverter {
168 let reg = GLOBAL_OBJECT_REGISTRY.read().unwrap();
169 let reg = reg.as_ref().unwrap();
170 reg.pyobject_converter.as_ref().unwrap().clone()
171}
172
173pub fn get_object_array_getter() -> ObjectArrayGetter {
174 let reg = GLOBAL_OBJECT_REGISTRY.read().unwrap();
175 reg.as_ref().unwrap().array_getter.clone()
176}
177
178pub fn run_with_gil<R, F: FnOnce() -> R>(f: F) -> R {
183 let reg = GLOBAL_OBJECT_REGISTRY.read().unwrap();
184 let with_gil = reg.as_ref().unwrap().with_gil.clone();
185 let r = &mut None;
186 let f = &mut Some(f);
187 (with_gil)(&mut || {
188 *r = Some((f.take().unwrap())());
189 });
190 r.take().unwrap()
191}