1use arrow_schema::{DataType, FieldRef, IntervalUnit, TimeUnit};
8use sha2::{Digest, Sha256};
9
10use super::partition_key::{validate_key_type, PartitionKeyCodecError};
11
12pub const PARTITION_KEY_SCHEMA_VERSION: u16 = 1;
14pub const MAX_PARTITION_KEY_SCHEMA_BYTES: usize = 128 * 1024;
20
21const MAGIC: &[u8; 8] = b"LDBPKS\0\0";
22
23#[derive(Clone, Debug, Eq, PartialEq)]
28pub struct PartitionKeySchemaV1 {
29 bytes: Box<[u8]>,
30 sha256: [u8; 32],
31}
32
33impl PartitionKeySchemaV1 {
34 pub fn try_new(fields: &[FieldRef]) -> Result<Self, PartitionKeyCodecError> {
44 super::partition_key::validate_key_fields(fields)?;
45
46 let mut output = DescriptorWriter::new()?;
47 output.write_len(fields.len())?;
48 for (index, field) in fields.iter().enumerate() {
49 output.write_bool(field.is_nullable())?;
50 write_data_type(&mut output, field.data_type(), index)?;
51 }
52
53 let sha256 = Sha256::digest(&output.bytes).into();
54 Ok(Self {
55 bytes: output.bytes.into_boxed_slice(),
56 sha256,
57 })
58 }
59
60 #[must_use]
62 pub fn as_bytes(&self) -> &[u8] {
63 &self.bytes
64 }
65
66 #[must_use]
68 pub const fn sha256(&self) -> [u8; 32] {
69 self.sha256
70 }
71}
72
73struct DescriptorWriter {
74 bytes: Vec<u8>,
75}
76
77impl DescriptorWriter {
78 fn new() -> Result<Self, PartitionKeyCodecError> {
79 let mut writer = Self { bytes: Vec::new() };
80 writer.write_raw(MAGIC)?;
81 writer.write_raw(&PARTITION_KEY_SCHEMA_VERSION.to_be_bytes())?;
82 Ok(writer)
83 }
84
85 fn write_u8(&mut self, value: u8) -> Result<(), PartitionKeyCodecError> {
86 self.write_raw(&[value])
87 }
88
89 fn write_bool(&mut self, value: bool) -> Result<(), PartitionKeyCodecError> {
90 self.write_u8(u8::from(value))
91 }
92
93 fn write_len(&mut self, value: usize) -> Result<(), PartitionKeyCodecError> {
94 #[allow(clippy::cast_possible_truncation)]
95 self.write_raw(&(value as u64).to_be_bytes())
96 }
97
98 fn write_bytes(&mut self, value: &[u8]) -> Result<(), PartitionKeyCodecError> {
99 self.write_len(value.len())?;
100 self.write_raw(value)
101 }
102
103 fn write_raw(&mut self, value: &[u8]) -> Result<(), PartitionKeyCodecError> {
104 let next_len = self.bytes.len().checked_add(value.len()).ok_or(
105 PartitionKeyCodecError::KeySchemaDescriptorTooLarge {
106 limit: MAX_PARTITION_KEY_SCHEMA_BYTES,
107 },
108 )?;
109 if next_len > MAX_PARTITION_KEY_SCHEMA_BYTES {
110 return Err(PartitionKeyCodecError::KeySchemaDescriptorTooLarge {
111 limit: MAX_PARTITION_KEY_SCHEMA_BYTES,
112 });
113 }
114 if next_len > self.bytes.capacity() {
115 let target_capacity = self
116 .bytes
117 .capacity()
118 .max(256)
119 .saturating_mul(2)
120 .max(next_len)
121 .min(MAX_PARTITION_KEY_SCHEMA_BYTES);
122 self.bytes
123 .try_reserve_exact(target_capacity - self.bytes.len())
124 .map_err(|_| PartitionKeyCodecError::KeySchemaDescriptorTooLarge {
125 limit: MAX_PARTITION_KEY_SCHEMA_BYTES,
126 })?;
127 }
128 if self.bytes.capacity() > MAX_PARTITION_KEY_SCHEMA_BYTES {
129 return Err(PartitionKeyCodecError::KeySchemaDescriptorTooLarge {
130 limit: MAX_PARTITION_KEY_SCHEMA_BYTES,
131 });
132 }
133 self.bytes.extend_from_slice(value);
134 Ok(())
135 }
136}
137
138fn write_data_type(
142 output: &mut DescriptorWriter,
143 data_type: &DataType,
144 index: usize,
145) -> Result<(), PartitionKeyCodecError> {
146 validate_key_type(data_type, index, 0)?;
147 match data_type {
148 DataType::Null => output.write_u8(0),
149 DataType::Boolean => output.write_u8(1),
150 DataType::Int8 => output.write_u8(2),
151 DataType::Int16 => output.write_u8(3),
152 DataType::Int32 => output.write_u8(4),
153 DataType::Int64 => output.write_u8(5),
154 DataType::UInt8 => output.write_u8(6),
155 DataType::UInt16 => output.write_u8(7),
156 DataType::UInt32 => output.write_u8(8),
157 DataType::UInt64 => output.write_u8(9),
158 DataType::Timestamp(unit, timezone) => {
159 output.write_u8(10)?;
160 write_time_unit(output, unit)?;
161 match timezone {
162 None => output.write_u8(0),
163 Some(timezone) => {
164 output.write_u8(1)?;
165 output.write_bytes(timezone.as_bytes())
166 }
167 }
168 }
169 DataType::Date32 => output.write_u8(11),
170 DataType::Date64 => output.write_u8(12),
171 DataType::Time32(unit) => {
172 output.write_u8(13)?;
173 write_time_unit(output, unit)
174 }
175 DataType::Time64(unit) => {
176 output.write_u8(14)?;
177 write_time_unit(output, unit)
178 }
179 DataType::Duration(unit) => {
180 output.write_u8(15)?;
181 write_time_unit(output, unit)
182 }
183 DataType::Interval(unit) => {
184 output.write_u8(16)?;
185 write_interval_unit(output, unit)
186 }
187 DataType::Binary => output.write_u8(17),
188 DataType::FixedSizeBinary(width) => {
189 output.write_u8(18)?;
190 output.write_raw(&width.to_be_bytes())
191 }
192 DataType::LargeBinary => output.write_u8(19),
193 DataType::BinaryView => output.write_u8(20),
194 DataType::Utf8 => output.write_u8(21),
195 DataType::LargeUtf8 => output.write_u8(22),
196 DataType::Utf8View => output.write_u8(23),
197 DataType::Dictionary(_, values) => write_data_type(output, values, index),
198 DataType::Decimal32(precision, scale) => {
199 output.write_u8(24)?;
200 output.write_u8(*precision)?;
201 output.write_raw(&scale.to_be_bytes())
202 }
203 DataType::Decimal64(precision, scale) => {
204 output.write_u8(25)?;
205 output.write_u8(*precision)?;
206 output.write_raw(&scale.to_be_bytes())
207 }
208 DataType::Decimal128(precision, scale) => {
209 output.write_u8(26)?;
210 output.write_u8(*precision)?;
211 output.write_raw(&scale.to_be_bytes())
212 }
213 DataType::Decimal256(precision, scale) => {
214 output.write_u8(27)?;
215 output.write_u8(*precision)?;
216 output.write_raw(&scale.to_be_bytes())
217 }
218 DataType::Float16
219 | DataType::Float32
220 | DataType::Float64
221 | DataType::List(_)
222 | DataType::ListView(_)
223 | DataType::FixedSizeList(_, _)
224 | DataType::LargeList(_)
225 | DataType::LargeListView(_)
226 | DataType::Struct(_)
227 | DataType::Union(_, _)
228 | DataType::Map(_, _)
229 | DataType::RunEndEncoded(_, _) => Err(PartitionKeyCodecError::UnsupportedKeyTypeFamily {
230 index,
231 family: "non-scalar",
232 }),
233 }
234}
235
236fn write_time_unit(
237 output: &mut DescriptorWriter,
238 unit: &TimeUnit,
239) -> Result<(), PartitionKeyCodecError> {
240 output.write_u8(match unit {
241 TimeUnit::Second => 0,
242 TimeUnit::Millisecond => 1,
243 TimeUnit::Microsecond => 2,
244 TimeUnit::Nanosecond => 3,
245 })
246}
247
248fn write_interval_unit(
249 output: &mut DescriptorWriter,
250 unit: &IntervalUnit,
251) -> Result<(), PartitionKeyCodecError> {
252 output.write_u8(match unit {
253 IntervalUnit::YearMonth => 0,
254 IntervalUnit::DayTime => 1,
255 IntervalUnit::MonthDayNano => 2,
256 })
257}