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::ArrayRef;
11use arrow::array::builder::ArrayBuilder;
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>;
24
25pub struct ObjectRegistry {
26 pub builder_constructor: BuilderConstructor,
28 object_converter: Option<ObjectConverter>,
30 pub physical_dtype: ArrowDataType,
31}
32
33impl Debug for ObjectRegistry {
34 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
35 write!(f, "object-registry")
36 }
37}
38
39static GLOBAL_OBJECT_REGISTRY: LazyLock<RwLock<Option<ObjectRegistry>>> =
40 LazyLock::new(Default::default);
41
42pub trait AnonymousObjectBuilder: ArrayBuilder {
45 fn as_array_builder(self: Box<Self>) -> Box<dyn ArrayBuilder>;
46
47 unsafe fn from_chunks(self: Box<Self>, chunks: Vec<ArrayRef>) -> Series;
50
51 fn append_null(&mut self);
53
54 fn append_value(&mut self, value: &dyn Any);
58
59 fn append_option(&mut self, value: Option<&dyn Any>) {
60 match value {
61 None => self.append_null(),
62 Some(v) => self.append_value(v),
63 }
64 }
65
66 fn to_series(&mut self) -> Series;
69
70 fn get_list_builder(
71 &self,
72 name: PlSmallStr,
73 values_capacity: usize,
74 list_capacity: usize,
75 ) -> Box<dyn ListBuilderTrait>;
76}
77
78impl<T: PolarsObject> AnonymousObjectBuilder for ObjectChunkedBuilder<T> {
79 unsafe fn from_chunks(self: Box<Self>, chunks: Vec<ArrayRef>) -> Series {
82 ObjectChunked::<T>::new_with_compute_len(Arc::new(self.field().clone()), chunks)
83 .into_series()
84 }
85
86 fn as_array_builder(self: Box<Self>) -> Box<dyn ArrayBuilder> {
87 self
88 }
89
90 fn append_null(&mut self) {
91 self.append_null()
92 }
93
94 fn append_value(&mut self, value: &dyn Any) {
95 let value = value.downcast_ref::<T>().unwrap();
96 self.append_value(value.clone())
97 }
98
99 fn to_series(&mut self) -> Series {
100 let builder = std::mem::take(self);
101 builder.finish().into_series()
102 }
103 fn get_list_builder(
104 &self,
105 name: PlSmallStr,
106 values_capacity: usize,
107 list_capacity: usize,
108 ) -> Box<dyn ListBuilderTrait> {
109 Box::new(super::extension::list::ExtensionListBuilder::<T>::new(
110 name,
111 values_capacity,
112 list_capacity,
113 ))
114 }
115}
116
117pub fn register_object_builder(
118 builder_constructor: BuilderConstructor,
119 object_converter: ObjectConverter,
120 physical_dtype: ArrowDataType,
121) {
122 let reg = GLOBAL_OBJECT_REGISTRY.deref();
123 let mut reg = reg.write().unwrap();
124
125 *reg = Some(ObjectRegistry {
126 builder_constructor,
127 object_converter: Some(object_converter),
128 physical_dtype,
129 })
130}
131
132#[cold]
133pub fn get_object_physical_type() -> ArrowDataType {
134 let reg = GLOBAL_OBJECT_REGISTRY.read().unwrap();
135 let reg = reg.as_ref().unwrap();
136 reg.physical_dtype.clone()
137}
138
139pub fn get_object_builder(name: PlSmallStr, capacity: usize) -> Box<dyn AnonymousObjectBuilder> {
140 let reg = GLOBAL_OBJECT_REGISTRY.read().unwrap();
141 let reg = reg.as_ref().unwrap();
142 (reg.builder_constructor)(name, capacity)
143}
144
145pub fn get_object_converter() -> ObjectConverter {
146 let reg = GLOBAL_OBJECT_REGISTRY.read().unwrap();
147 let reg = reg.as_ref().unwrap();
148 reg.object_converter.as_ref().unwrap().clone()
149}