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