Skip to main content

readstat/
rs_var.rs

1//! Variable types and format classification for SAS data.
2//!
3//! [`ReadStatVarFormatClass`] classifies SAS format strings into semantic categories
4//! (Date, `DateTime`, Time, and their sub-second precision variants), which determines
5//! the Arrow data type used during conversion.
6//!
7//! [`ReadStatVarType`] and [`ReadStatVarTypeClass`] map `ReadStat` C type codes to Rust
8//! enums, used during schema construction and builder allocation.
9
10use num_derive::FromPrimitive;
11use serde::Serialize;
12
13/// Semantic classification of a SAS format string.
14///
15/// Determines the Arrow data type used for date/time/datetime variables:
16///
17/// | Variant | Arrow Type |
18/// |---------|------------|
19/// | `Date` | `Date32` |
20/// | `DateTime` | `Timestamp(Second)` |
21/// | `DateTimeWithMilliseconds` | `Timestamp(Millisecond)` |
22/// | `DateTimeWithMicroseconds` | `Timestamp(Microsecond)` |
23/// | `DateTimeWithNanoseconds` | `Timestamp(Nanosecond)` |
24/// | `Time` | `Time32(Second)` |
25/// | `TimeWithMilliseconds` | `Time32(Millisecond)` |
26/// | `TimeWithMicroseconds` | `Time64(Microsecond)` |
27/// | `TimeWithNanoseconds` | `Time64(Nanosecond)` |
28///
29/// This enum is `#[non_exhaustive]`: new precision levels or format classes
30/// may be added in minor releases.
31///
32/// # Time range note
33///
34/// SAS `TIME` values are stored as seconds since midnight, but SAS treats them
35/// as durations and permits values that are negative or exceed 86 399 s (one
36/// day). Such values are written into the Arrow `Time32`/`Time64` columns as-is,
37/// without clamping — so a column may legally hold a time-of-day outside the
38/// `[0, 86400)` range that consumers of Arrow time types might assume.
39#[non_exhaustive]
40#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
41pub enum ReadStatVarFormatClass {
42    /// Date format (e.g. `DATE9`, `MMDDYY10`). Maps to Arrow `Date32`.
43    Date,
44    /// `DateTime` format with second precision (e.g. `DATETIME22`).
45    DateTime,
46    /// `DateTime` format requesting millisecond output (e.g. `DATETIME22.3`).
47    DateTimeWithMilliseconds,
48    /// `DateTime` format requesting microsecond output (e.g. `DATETIME25.6`).
49    DateTimeWithMicroseconds,
50    /// `DateTime` format requesting nanosecond output (e.g. `DATETIME28.9`).
51    ///
52    /// An 8-byte SAS numeric at modern datetime magnitudes cannot distinguish
53    /// arbitrary nanoseconds. This variant preserves the format's requested
54    /// Arrow unit; it does not guarantee nanosecond fidelity in the source.
55    DateTimeWithNanoseconds,
56    /// Time format with second precision (e.g. `TIME8`).
57    Time,
58    /// Time format with millisecond precision (e.g. `TIME12.3`).
59    TimeWithMilliseconds,
60    /// Time format with microsecond precision (e.g. `TIME15.6`).
61    TimeWithMicroseconds,
62    /// Time format with nanosecond precision (e.g. `TIME18.9`).
63    TimeWithNanoseconds,
64}
65
66/// The storage type of a SAS variable, as reported by the `ReadStat` C library.
67///
68/// This enum is `#[non_exhaustive]`: it mirrors a C library enum that may gain
69/// variants. Match with a wildcard arm to remain forward-compatible.
70#[non_exhaustive]
71#[derive(Clone, Copy, Debug, FromPrimitive, Serialize)]
72#[allow(clippy::cast_possible_wrap)]
73pub enum ReadStatVarType {
74    /// Variable-length string.
75    String = readstat_sys::readstat_type_e_READSTAT_TYPE_STRING as isize,
76    /// 8-bit signed integer.
77    Int8 = readstat_sys::readstat_type_e_READSTAT_TYPE_INT8 as isize,
78    /// 16-bit signed integer.
79    Int16 = readstat_sys::readstat_type_e_READSTAT_TYPE_INT16 as isize,
80    /// 32-bit signed integer.
81    Int32 = readstat_sys::readstat_type_e_READSTAT_TYPE_INT32 as isize,
82    /// 32-bit floating point.
83    Float = readstat_sys::readstat_type_e_READSTAT_TYPE_FLOAT as isize,
84    /// 64-bit floating point (also used for dates/times via format class).
85    Double = readstat_sys::readstat_type_e_READSTAT_TYPE_DOUBLE as isize,
86    /// String reference (interned string).
87    StringRef = readstat_sys::readstat_type_e_READSTAT_TYPE_STRING_REF as isize,
88    /// Unknown or unrecognized type.
89    Unknown,
90}
91
92/// High-level type class of a SAS variable: string or numeric.
93///
94/// This enum is `#[non_exhaustive]`: it mirrors a C library enum that may gain
95/// variants. Match with a wildcard arm to remain forward-compatible.
96#[non_exhaustive]
97#[derive(Clone, Copy, Debug, FromPrimitive, Serialize)]
98#[allow(clippy::cast_possible_wrap)]
99pub enum ReadStatVarTypeClass {
100    /// Character/string data.
101    String = readstat_sys::readstat_type_class_e_READSTAT_TYPE_CLASS_STRING as isize,
102    /// Numeric data (integers, floats, dates, times).
103    Numeric = readstat_sys::readstat_type_class_e_READSTAT_TYPE_CLASS_NUMERIC as isize,
104}