1use std::{marker::PhantomData, sync::Arc};
4
5#[cfg(feature = "views")]
6use arrow_array::Array;
7use arrow_array::{
8 PrimitiveArray,
9 builder::PrimitiveBuilder,
10 types::{
11 Date32Type, Date64Type, DurationMicrosecondType, DurationMillisecondType,
12 DurationNanosecondType, DurationSecondType, Time32MillisecondType, Time32SecondType,
13 Time64MicrosecondType, Time64NanosecondType, TimestampMicrosecondType,
14 TimestampMillisecondType, TimestampNanosecondType, TimestampSecondType,
15 },
16};
17use arrow_schema::{DataType, TimeUnit};
18
19use super::ArrowBinding;
20#[cfg(feature = "views")]
21use super::ArrowBindingView;
22
23pub trait TimeUnitSpec {
27 type Arrow: arrow_array::types::ArrowTimestampType;
29 fn unit() -> TimeUnit;
31}
32
33pub enum Second {}
35impl TimeUnitSpec for Second {
36 type Arrow = TimestampSecondType;
37 fn unit() -> TimeUnit {
38 TimeUnit::Second
39 }
40}
41
42pub enum Millisecond {}
44impl TimeUnitSpec for Millisecond {
45 type Arrow = TimestampMillisecondType;
46 fn unit() -> TimeUnit {
47 TimeUnit::Millisecond
48 }
49}
50
51pub enum Microsecond {}
53impl TimeUnitSpec for Microsecond {
54 type Arrow = TimestampMicrosecondType;
55 fn unit() -> TimeUnit {
56 TimeUnit::Microsecond
57 }
58}
59
60pub enum Nanosecond {}
62impl TimeUnitSpec for Nanosecond {
63 type Arrow = TimestampNanosecondType;
64 fn unit() -> TimeUnit {
65 TimeUnit::Nanosecond
66 }
67}
68
69#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
71pub struct Timestamp<U: TimeUnitSpec>(i64, PhantomData<U>);
72impl<U: TimeUnitSpec> Timestamp<U> {
73 #[inline]
75 #[must_use]
76 pub fn new(value: i64) -> Self {
77 Self(value, PhantomData)
78 }
79 #[inline]
81 #[must_use]
82 pub fn value(&self) -> i64 {
83 self.0
84 }
85 #[inline]
87 #[must_use]
88 pub fn into_value(self) -> i64 {
89 self.0
90 }
91}
92impl<U: TimeUnitSpec> ArrowBinding for Timestamp<U> {
93 type Builder = PrimitiveBuilder<U::Arrow>;
94 type Array = PrimitiveArray<U::Arrow>;
95 fn data_type() -> DataType {
96 DataType::Timestamp(U::unit(), None)
97 }
98 fn new_builder(capacity: usize) -> Self::Builder {
99 PrimitiveBuilder::<U::Arrow>::with_capacity(capacity)
100 }
101 fn append_value(b: &mut Self::Builder, v: &Self) {
102 b.append_value(v.0);
103 }
104 fn append_null(b: &mut Self::Builder) {
105 b.append_null();
106 }
107 fn finish(mut b: Self::Builder) -> Self::Array {
108 b.finish()
109 }
110}
111
112#[cfg(feature = "views")]
113impl<U: TimeUnitSpec + 'static> ArrowBindingView for Timestamp<U> {
114 type Array = PrimitiveArray<U::Arrow>;
115 type View<'a> = Timestamp<U>;
116
117 fn get_view(
118 array: &Self::Array,
119 index: usize,
120 ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
121 if index >= array.len() {
122 return Err(crate::schema::ViewAccessError::OutOfBounds {
123 index,
124 len: array.len(),
125 field_name: None,
126 });
127 }
128 if array.is_null(index) {
129 return Err(crate::schema::ViewAccessError::UnexpectedNull {
130 index,
131 field_name: None,
132 });
133 }
134 Ok(Timestamp::new(array.value(index)))
135 }
136}
137
138pub trait TimeZoneSpec {
140 const NAME: Option<&'static str>;
142}
143
144pub enum Utc {}
146impl TimeZoneSpec for Utc {
147 const NAME: Option<&'static str> = Some("UTC");
148}
149
150#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
152pub struct TimestampTz<U: TimeUnitSpec, Z: TimeZoneSpec>(i64, PhantomData<(U, Z)>);
153impl<U: TimeUnitSpec, Z: TimeZoneSpec> TimestampTz<U, Z> {
154 #[inline]
156 #[must_use]
157 pub fn new(value: i64) -> Self {
158 Self(value, PhantomData)
159 }
160 #[inline]
162 #[must_use]
163 pub fn value(&self) -> i64 {
164 self.0
165 }
166 #[inline]
168 #[must_use]
169 pub fn into_value(self) -> i64 {
170 self.0
171 }
172}
173impl<U: TimeUnitSpec, Z: TimeZoneSpec> ArrowBinding for TimestampTz<U, Z> {
174 type Builder = PrimitiveBuilder<U::Arrow>;
175 type Array = PrimitiveArray<U::Arrow>;
176 fn data_type() -> DataType {
177 DataType::Timestamp(U::unit(), Z::NAME.map(Arc::<str>::from))
178 }
179 fn new_builder(capacity: usize) -> Self::Builder {
180 PrimitiveBuilder::<U::Arrow>::with_capacity(capacity)
181 }
182 fn append_value(b: &mut Self::Builder, v: &Self) {
183 b.append_value(v.0);
184 }
185 fn append_null(b: &mut Self::Builder) {
186 b.append_null();
187 }
188 fn finish(mut b: Self::Builder) -> Self::Array {
189 b.finish()
190 }
191}
192
193#[cfg(feature = "views")]
194impl<U: TimeUnitSpec + 'static, Z: TimeZoneSpec + 'static> ArrowBindingView for TimestampTz<U, Z> {
195 type Array = PrimitiveArray<U::Arrow>;
196 type View<'a> = TimestampTz<U, Z>;
197
198 fn get_view(
199 array: &Self::Array,
200 index: usize,
201 ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
202 if index >= array.len() {
203 return Err(crate::schema::ViewAccessError::OutOfBounds {
204 index,
205 len: array.len(),
206 field_name: None,
207 });
208 }
209 if array.is_null(index) {
210 return Err(crate::schema::ViewAccessError::UnexpectedNull {
211 index,
212 field_name: None,
213 });
214 }
215 Ok(TimestampTz::new(array.value(index)))
216 }
217}
218
219#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
223pub struct Date32(i32);
224impl Date32 {
225 #[inline]
227 #[must_use]
228 pub fn new(value: i32) -> Self {
229 Self(value)
230 }
231 #[inline]
233 #[must_use]
234 pub fn value(&self) -> i32 {
235 self.0
236 }
237 #[inline]
239 #[must_use]
240 pub fn into_value(self) -> i32 {
241 self.0
242 }
243}
244impl ArrowBinding for Date32 {
245 type Builder = PrimitiveBuilder<Date32Type>;
246 type Array = PrimitiveArray<Date32Type>;
247 fn data_type() -> DataType {
248 DataType::Date32
249 }
250 fn new_builder(capacity: usize) -> Self::Builder {
251 PrimitiveBuilder::<Date32Type>::with_capacity(capacity)
252 }
253 fn append_value(b: &mut Self::Builder, v: &Self) {
254 b.append_value(v.0);
255 }
256 fn append_null(b: &mut Self::Builder) {
257 b.append_null();
258 }
259 fn finish(mut b: Self::Builder) -> Self::Array {
260 b.finish()
261 }
262}
263
264#[cfg(feature = "views")]
265impl ArrowBindingView for Date32 {
266 type Array = PrimitiveArray<Date32Type>;
267 type View<'a> = Date32;
268
269 fn get_view(
270 array: &Self::Array,
271 index: usize,
272 ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
273 if index >= array.len() {
274 return Err(crate::schema::ViewAccessError::OutOfBounds {
275 index,
276 len: array.len(),
277 field_name: None,
278 });
279 }
280 if array.is_null(index) {
281 return Err(crate::schema::ViewAccessError::UnexpectedNull {
282 index,
283 field_name: None,
284 });
285 }
286 Ok(Date32::new(array.value(index)))
287 }
288}
289
290#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
292pub struct Date64(i64);
293impl Date64 {
294 #[inline]
296 #[must_use]
297 pub fn new(value: i64) -> Self {
298 Self(value)
299 }
300 #[inline]
302 #[must_use]
303 pub fn value(&self) -> i64 {
304 self.0
305 }
306 #[inline]
308 #[must_use]
309 pub fn into_value(self) -> i64 {
310 self.0
311 }
312}
313impl ArrowBinding for Date64 {
314 type Builder = PrimitiveBuilder<Date64Type>;
315 type Array = PrimitiveArray<Date64Type>;
316 fn data_type() -> DataType {
317 DataType::Date64
318 }
319 fn new_builder(capacity: usize) -> Self::Builder {
320 PrimitiveBuilder::<Date64Type>::with_capacity(capacity)
321 }
322 fn append_value(b: &mut Self::Builder, v: &Self) {
323 b.append_value(v.0);
324 }
325 fn append_null(b: &mut Self::Builder) {
326 b.append_null();
327 }
328 fn finish(mut b: Self::Builder) -> Self::Array {
329 b.finish()
330 }
331}
332
333#[cfg(feature = "views")]
334impl ArrowBindingView for Date64 {
335 type Array = PrimitiveArray<Date64Type>;
336 type View<'a> = Date64;
337
338 fn get_view(
339 array: &Self::Array,
340 index: usize,
341 ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
342 if index >= array.len() {
343 return Err(crate::schema::ViewAccessError::OutOfBounds {
344 index,
345 len: array.len(),
346 field_name: None,
347 });
348 }
349 if array.is_null(index) {
350 return Err(crate::schema::ViewAccessError::UnexpectedNull {
351 index,
352 field_name: None,
353 });
354 }
355 Ok(Date64::new(array.value(index)))
356 }
357}
358
359pub trait Time32UnitSpec {
363 type Arrow;
364 fn unit() -> TimeUnit;
365}
366impl Time32UnitSpec for Second {
367 type Arrow = Time32SecondType;
368 fn unit() -> TimeUnit {
369 TimeUnit::Second
370 }
371}
372impl Time32UnitSpec for Millisecond {
373 type Arrow = Time32MillisecondType;
374 fn unit() -> TimeUnit {
375 TimeUnit::Millisecond
376 }
377}
378
379pub struct Time32<U: Time32UnitSpec>(i32, PhantomData<U>);
381impl<U: Time32UnitSpec> Time32<U> {
382 #[inline]
384 #[must_use]
385 pub fn new(value: i32) -> Self {
386 Self(value, PhantomData)
387 }
388 #[inline]
390 #[must_use]
391 pub fn value(&self) -> i32 {
392 self.0
393 }
394 #[inline]
396 #[must_use]
397 pub fn into_value(self) -> i32 {
398 self.0
399 }
400}
401impl<U: Time32UnitSpec> ArrowBinding for Time32<U>
402where
403 U::Arrow: arrow_array::types::ArrowPrimitiveType<Native = i32>,
404{
405 type Builder = PrimitiveBuilder<U::Arrow>;
406 type Array = PrimitiveArray<U::Arrow>;
407 fn data_type() -> DataType {
408 DataType::Time32(U::unit())
409 }
410 fn new_builder(capacity: usize) -> Self::Builder {
411 PrimitiveBuilder::<U::Arrow>::with_capacity(capacity)
412 }
413 fn append_value(b: &mut Self::Builder, v: &Self) {
414 b.append_value(v.0 as <U::Arrow as arrow_array::types::ArrowPrimitiveType>::Native);
415 }
416 fn append_null(b: &mut Self::Builder) {
417 b.append_null();
418 }
419 fn finish(mut b: Self::Builder) -> Self::Array {
420 b.finish()
421 }
422}
423
424#[cfg(feature = "views")]
425impl<U: Time32UnitSpec + 'static> ArrowBindingView for Time32<U>
426where
427 U::Arrow: arrow_array::types::ArrowPrimitiveType<Native = i32>,
428{
429 type Array = PrimitiveArray<U::Arrow>;
430 type View<'a> = Time32<U>;
431
432 fn get_view(
433 array: &Self::Array,
434 index: usize,
435 ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
436 if index >= array.len() {
437 return Err(crate::schema::ViewAccessError::OutOfBounds {
438 index,
439 len: array.len(),
440 field_name: None,
441 });
442 }
443 if array.is_null(index) {
444 return Err(crate::schema::ViewAccessError::UnexpectedNull {
445 index,
446 field_name: None,
447 });
448 }
449 Ok(Time32::new(array.value(index)))
450 }
451}
452
453pub trait Time64UnitSpec {
455 type Arrow;
456 fn unit() -> TimeUnit;
457}
458impl Time64UnitSpec for Microsecond {
459 type Arrow = Time64MicrosecondType;
460 fn unit() -> TimeUnit {
461 TimeUnit::Microsecond
462 }
463}
464impl Time64UnitSpec for Nanosecond {
465 type Arrow = Time64NanosecondType;
466 fn unit() -> TimeUnit {
467 TimeUnit::Nanosecond
468 }
469}
470
471pub struct Time64<U: Time64UnitSpec>(i64, PhantomData<U>);
473impl<U: Time64UnitSpec> Time64<U> {
474 #[inline]
476 #[must_use]
477 pub fn new(value: i64) -> Self {
478 Self(value, PhantomData)
479 }
480 #[inline]
482 #[must_use]
483 pub fn value(&self) -> i64 {
484 self.0
485 }
486 #[inline]
488 #[must_use]
489 pub fn into_value(self) -> i64 {
490 self.0
491 }
492}
493impl<U: Time64UnitSpec> ArrowBinding for Time64<U>
494where
495 U::Arrow: arrow_array::types::ArrowPrimitiveType<Native = i64>,
496{
497 type Builder = PrimitiveBuilder<U::Arrow>;
498 type Array = PrimitiveArray<U::Arrow>;
499 fn data_type() -> DataType {
500 DataType::Time64(U::unit())
501 }
502 fn new_builder(capacity: usize) -> Self::Builder {
503 PrimitiveBuilder::<U::Arrow>::with_capacity(capacity)
504 }
505 fn append_value(b: &mut Self::Builder, v: &Self) {
506 b.append_value(v.0 as <U::Arrow as arrow_array::types::ArrowPrimitiveType>::Native);
507 }
508 fn append_null(b: &mut Self::Builder) {
509 b.append_null();
510 }
511 fn finish(mut b: Self::Builder) -> Self::Array {
512 b.finish()
513 }
514}
515
516#[cfg(feature = "views")]
517impl<U: Time64UnitSpec + 'static> ArrowBindingView for Time64<U>
518where
519 U::Arrow: arrow_array::types::ArrowPrimitiveType<Native = i64>,
520{
521 type Array = PrimitiveArray<U::Arrow>;
522 type View<'a> = Time64<U>;
523
524 fn get_view(
525 array: &Self::Array,
526 index: usize,
527 ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
528 if index >= array.len() {
529 return Err(crate::schema::ViewAccessError::OutOfBounds {
530 index,
531 len: array.len(),
532 field_name: None,
533 });
534 }
535 if array.is_null(index) {
536 return Err(crate::schema::ViewAccessError::UnexpectedNull {
537 index,
538 field_name: None,
539 });
540 }
541 Ok(Time64::new(array.value(index)))
542 }
543}
544
545pub trait DurationUnitSpec {
549 type Arrow;
550 fn unit() -> TimeUnit;
551}
552impl DurationUnitSpec for Second {
553 type Arrow = DurationSecondType;
554 fn unit() -> TimeUnit {
555 TimeUnit::Second
556 }
557}
558impl DurationUnitSpec for Millisecond {
559 type Arrow = DurationMillisecondType;
560 fn unit() -> TimeUnit {
561 TimeUnit::Millisecond
562 }
563}
564impl DurationUnitSpec for Microsecond {
565 type Arrow = DurationMicrosecondType;
566 fn unit() -> TimeUnit {
567 TimeUnit::Microsecond
568 }
569}
570impl DurationUnitSpec for Nanosecond {
571 type Arrow = DurationNanosecondType;
572 fn unit() -> TimeUnit {
573 TimeUnit::Nanosecond
574 }
575}
576
577#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
579pub struct Duration<U: DurationUnitSpec>(i64, PhantomData<U>);
580impl<U: DurationUnitSpec> Duration<U> {
581 #[inline]
583 #[must_use]
584 pub fn new(value: i64) -> Self {
585 Self(value, PhantomData)
586 }
587 #[inline]
589 #[must_use]
590 pub fn value(&self) -> i64 {
591 self.0
592 }
593 #[inline]
595 #[must_use]
596 pub fn into_value(self) -> i64 {
597 self.0
598 }
599}
600impl<U: DurationUnitSpec> ArrowBinding for Duration<U>
601where
602 U::Arrow: arrow_array::types::ArrowPrimitiveType<Native = i64>,
603{
604 type Builder = PrimitiveBuilder<U::Arrow>;
605 type Array = PrimitiveArray<U::Arrow>;
606 fn data_type() -> DataType {
607 DataType::Duration(U::unit())
608 }
609 fn new_builder(capacity: usize) -> Self::Builder {
610 PrimitiveBuilder::<U::Arrow>::with_capacity(capacity)
611 }
612 fn append_value(b: &mut Self::Builder, v: &Self) {
613 b.append_value(v.0);
614 }
615 fn append_null(b: &mut Self::Builder) {
616 b.append_null();
617 }
618 fn finish(mut b: Self::Builder) -> Self::Array {
619 b.finish()
620 }
621}
622
623#[cfg(feature = "views")]
624impl<U: DurationUnitSpec + 'static> ArrowBindingView for Duration<U>
625where
626 U::Arrow: arrow_array::types::ArrowPrimitiveType<Native = i64>,
627{
628 type Array = PrimitiveArray<U::Arrow>;
629 type View<'a> = Duration<U>;
630
631 fn get_view(
632 array: &Self::Array,
633 index: usize,
634 ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
635 if index >= array.len() {
636 return Err(crate::schema::ViewAccessError::OutOfBounds {
637 index,
638 len: array.len(),
639 field_name: None,
640 });
641 }
642 if array.is_null(index) {
643 return Err(crate::schema::ViewAccessError::UnexpectedNull {
644 index,
645 field_name: None,
646 });
647 }
648 Ok(Duration::new(array.value(index)))
649 }
650}