1pub use crate::native_types::Kind;
3use crate::{
4 decimal::{Error, Result},
5 native_types::TYPES,
6};
7use chrono::Datelike;
8use std::ffi::c_char;
9use std::hash::{Hash, Hasher};
10
11pub fn encode(kind: Kind, text: &str) -> Result<Vec<u8>> {
12 let payload = match kind {
13 Kind::Uuid => uuid::Uuid::parse_str(text)
14 .map_err(|e| Error(e.to_string()))?
15 .as_bytes()
16 .to_vec(),
17 Kind::Decimal => return crate::decimal::encode(text),
18 Kind::Uint8 | Kind::Uint16 | Kind::Uint32 | Kind::Uint64 => {
19 return crate::unsigned::encode(kind, text);
20 }
21 _ => crate::temporal::encode(kind, text)?,
22 };
23 let descriptor = TYPES.iter().find(|d| d.kind == kind).unwrap();
24 let mut bytes = vec![descriptor.tag];
25 bytes.extend(payload);
26 Ok(bytes)
27}
28
29pub fn text(kind: Kind, bytes: &[u8]) -> Result<String> {
30 match kind {
31 Kind::Uuid => Ok(uuid::Uuid::from_bytes(
32 bytes
33 .try_into()
34 .map_err(|_| Error("invalid UUID storage".into()))?,
35 )
36 .to_string()),
37 Kind::Uint8 | Kind::Uint16 | Kind::Uint32 | Kind::Uint64 => {
38 Ok(crate::unsigned::read(bytes).to_string())
39 }
40 Kind::Decimal => std::str::from_utf8(bytes)
41 .map(str::to_owned)
42 .map_err(|e| Error(e.to_string())),
43 _ => crate::temporal::text(kind, bytes),
44 }
45}
46
47pub fn decode(bytes: &[u8]) -> Option<(Kind, String)> {
48 if bytes.is_empty() {
49 return None;
50 }
51 let descriptor = TYPES
52 .iter()
53 .find(|d| d.tag == bytes[0] && d.kind != Kind::Decimal)?;
54 if bytes.len() != 1 + descriptor.payload_size {
55 return None;
56 }
57 Some((descriptor.kind, text(descriptor.kind, &bytes[1..]).ok()?))
58}
59
60pub fn canonical(kind: Kind, value: &str) -> Result<String> {
61 let bytes = encode(kind, value)?;
62 text(kind, &bytes[1..])
63}
64
65pub fn cast(target: Kind, source: Kind, value: &str) -> Result<String> {
66 let bytes = encode(source, value)?;
67 if crate::unsigned::is_unsigned(target as i32) {
68 let converted =
69 crate::unsigned::evaluate(0, target as i32, source as i32, &bytes[1..], -3, &[])?;
70 return text(target, &converted[1..]);
71 }
72 if target == Kind::Decimal && crate::unsigned::is_unsigned(source as i32) {
73 return canonical(target, &text(source, &bytes[1..])?);
74 }
75 let payload = if target == source {
76 bytes[1..].to_vec()
77 } else {
78 crate::temporal::cast(target, source, &bytes[1..], false)?
79 };
80 text(target, &payload)
81}
82
83#[repr(C)]
84struct FunctionArgument {
85 kind: i32,
86 data: *const c_char,
87 length: i32,
88}
89
90#[unsafe(no_mangle)]
91unsafe extern "C" fn boxdb_native_function(
92 function: i32,
93 argc: i32,
94 args: *const FunctionArgument,
95 out: *mut *mut c_char,
96 out_len: *mut i32,
97) -> i32 {
98 let result = (|| {
99 if !(0..=7).contains(&argc) {
100 return Err(Error("invalid temporal function argument count".into()));
101 }
102 let args = unsafe { std::slice::from_raw_parts(args, argc as usize) }
103 .iter()
104 .map(|arg| crate::temporal_functions::Argument {
105 kind: arg.kind,
106 bytes: unsafe { input(arg.data, arg.length) },
107 })
108 .collect::<Vec<_>>();
109 let (kind, payload) = crate::temporal_functions::evaluate(function, &args)?;
110 let descriptor = TYPES.iter().find(|d| d.kind == kind).unwrap();
111 let mut bytes = vec![descriptor.tag];
112 bytes.extend(payload);
113 Ok(bytes)
114 })();
115 match result {
116 Ok(bytes) => unsafe { crate::decimal::output(&bytes, out, out_len) },
117 Err(error) => {
118 let rc = unsafe { crate::decimal::output(error.0.as_bytes(), out, out_len) };
119 if rc == crate::SQLITE_OK {
120 crate::SQLITE_ERROR
121 } else {
122 rc
123 }
124 }
125 }
126}
127
128fn ordering_key(kind: i32, bytes: &[u8]) -> i128 {
129 match kind {
130 3 | 5 => {
131 i128::from(i64::from_be_bytes(bytes[..8].try_into().unwrap())) * crate::temporal::SECOND
132 + i128::from(u32::from_be_bytes(bytes[8..12].try_into().unwrap()))
133 }
134 4 => {
135 (i128::from(i32::from_be_bytes(bytes[..4].try_into().unwrap()))
136 - i128::from(
137 chrono::NaiveDate::from_ymd_opt(1970, 1, 1)
138 .unwrap()
139 .num_days_from_ce(),
140 ))
141 * crate::temporal::DAY
142 }
143 11 => i128::from(u64::from_be_bytes(bytes.try_into().unwrap())),
144 6 => {
145 let value = crate::temporal::read_interval(bytes).unwrap();
146 (i128::from(value.months) * 30 + i128::from(value.days)) * crate::temporal::DAY
147 + i128::from(value.micros)
148 }
149 _ => 0,
150 }
151}
152
153#[unsafe(no_mangle)]
154unsafe extern "C" fn boxdb_native_compare(
155 kind: i32,
156 a: *const c_char,
157 na: i32,
158 kind_b: i32,
159 b: *const c_char,
160 nb: i32,
161) -> i32 {
162 let a = unsafe { input(a, na) };
163 let b = unsafe { input(b, nb) };
164 if kind == 2 {
165 a.cmp(b) as i32
166 } else {
167 ordering_key(kind, a).cmp(&ordering_key(kind_b, b)) as i32
168 }
169}
170
171#[unsafe(no_mangle)]
172unsafe extern "C" fn boxdb_native_hash(kind: i32, data: *const c_char, length: i32) -> u64 {
173 let bytes = unsafe { input(data, length) };
174 if crate::unsigned::is_unsigned(kind) {
175 return crate::unsigned::read(bytes).min(i64::MAX as u64);
178 }
179 let mut hash = std::collections::hash_map::DefaultHasher::new();
180 (if matches!(kind, 4 | 5) { 4 } else { kind }).hash(&mut hash);
181 if matches!(kind, 4 | 5 | 6) {
182 ordering_key(kind, bytes).hash(&mut hash);
183 } else {
184 bytes.hash(&mut hash);
185 }
186 hash.finish()
187}
188
189unsafe fn input<'a>(data: *const c_char, length: i32) -> &'a [u8] {
190 unsafe { std::slice::from_raw_parts(data.cast(), length as usize) }
191}
192
193#[unsafe(no_mangle)]
194unsafe extern "C" fn boxdb_native_text(
195 kind: i32,
196 data: *const c_char,
197 length: i32,
198 out: *mut *mut c_char,
199 out_len: *mut i32,
200) -> i32 {
201 let result = (|| {
202 let kind = TYPES
203 .iter()
204 .find(|d| d.kind as i32 == kind)
205 .ok_or_else(|| Error("unknown native type".into()))?
206 .kind;
207 text(kind, unsafe { input(data, length) })
208 })();
209 match result {
210 Ok(value) => unsafe { crate::decimal::output(value.as_bytes(), out, out_len) },
211 Err(error) => {
212 let rc = unsafe { crate::decimal::output(error.0.as_bytes(), out, out_len) };
213 if rc == crate::SQLITE_OK {
214 crate::SQLITE_ERROR
215 } else {
216 rc
217 }
218 }
219 }
220}
221
222#[unsafe(no_mangle)]
223unsafe extern "C" fn boxdb_native_eval(
224 operation: i32,
225 target: i32,
226 kind_a: i32,
227 data_a: *const c_char,
228 len_a: i32,
229 kind_b: i32,
230 data_b: *const c_char,
231 len_b: i32,
232 out: *mut *mut c_char,
233 out_len: *mut i32,
234 out_kind: *mut i32,
235) -> i32 {
236 let result = (|| {
237 if crate::unsigned::is_unsigned(target)
238 || crate::unsigned::is_unsigned(kind_a)
239 || crate::unsigned::is_unsigned(kind_b)
240 {
241 if target == 0 || crate::unsigned::is_unsigned(target) {
242 unsafe {
243 *out_kind = if target == 0 {
244 kind_a.max(kind_b)
245 } else {
246 target
247 };
248 }
249 return crate::unsigned::evaluate(
250 operation,
251 target,
252 kind_a,
253 unsafe { input(data_a, len_a) },
254 kind_b,
255 unsafe { input(data_b, len_b) },
256 );
257 }
258 }
259 if operation != 0 && operation != 8 {
260 let (kind, payload) = crate::temporal::operation(
261 operation,
262 kind_a,
263 unsafe { input(data_a, len_a) },
264 kind_b,
265 unsafe { input(data_b, len_b) },
266 )?;
267 unsafe {
268 *out_kind = kind;
269 }
270 if kind < 0 {
271 return Ok(payload);
272 }
273 let descriptor = TYPES.iter().find(|d| d.kind as i32 == kind).unwrap();
274 let mut bytes = vec![descriptor.tag];
275 bytes.extend(payload);
276 return Ok(bytes);
277 }
278 let kind = TYPES
279 .iter()
280 .find(|d| d.kind as i32 == target)
281 .ok_or_else(|| Error("unknown native type".into()))?
282 .kind;
283 unsafe {
284 *out_kind = kind as i32;
285 }
286 if kind_a > 0 {
287 let source = TYPES
288 .iter()
289 .find(|d| d.kind as i32 == kind_a)
290 .ok_or_else(|| Error("unknown native type".into()))?
291 .kind;
292 let input = unsafe { input(data_a, len_a) };
293 let payload = if kind == source {
294 text(kind, input)?;
295 input.to_vec()
296 } else {
297 crate::temporal::cast(kind, source, input, operation == 8)?
298 };
299 let descriptor = TYPES.iter().find(|d| d.kind == kind).unwrap();
300 let mut bytes = vec![descriptor.tag];
301 bytes.extend(payload);
302 return Ok(bytes);
303 }
304 if kind_a != 0 {
305 return Err(Error("unsupported native conversion".into()));
306 }
307 let text = std::str::from_utf8(unsafe { input(data_a, len_a) })
308 .map_err(|e| Error(e.to_string()))?;
309 encode(kind, text)
310 })();
311 match result {
312 Ok(bytes) => unsafe { crate::decimal::output(&bytes, out, out_len) },
313 Err(error) => {
314 let rc = unsafe { crate::decimal::output(error.0.as_bytes(), out, out_len) };
315 if rc == crate::SQLITE_OK {
316 crate::SQLITE_ERROR
317 } else {
318 rc
319 }
320 }
321 }
322}