Skip to main content

limbo_ext/
types.rs

1use std::fmt::Display;
2
3/// Error type is of type ExtError which can be
4/// either a user defined error or an error code
5#[repr(C)]
6#[derive(Debug, PartialEq, Eq, Clone, Copy)]
7pub enum ResultCode {
8    OK = 0,
9    Error = 1,
10    InvalidArgs = 2,
11    Unknown = 3,
12    OoM = 4,
13    Corrupt = 5,
14    NotFound = 6,
15    AlreadyExists = 7,
16    PermissionDenied = 8,
17    Aborted = 9,
18    OutOfRange = 10,
19    Unimplemented = 11,
20    Internal = 12,
21    Unavailable = 13,
22    CustomError = 14,
23    EOF = 15,
24    ReadOnly = 16,
25    RowID = 17,
26    Row = 18,
27    Interrupt = 19,
28    Busy = 20,
29}
30
31impl ResultCode {
32    pub fn is_ok(&self) -> bool {
33        matches!(self, Self::OK)
34    }
35
36    pub fn is_error(&self) -> bool {
37        !matches!(self, Self::OK | Self::RowID | Self::EOF)
38    }
39
40    pub fn has_error_set(&self) -> bool {
41        matches!(self, Self::CustomError)
42    }
43}
44
45impl Display for ResultCode {
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        match self {
48            ResultCode::OK => write!(f, "OK"),
49            ResultCode::Error => write!(f, "Error"),
50            ResultCode::InvalidArgs => write!(f, "Invalid Argument"),
51            ResultCode::Unknown => write!(f, "Unknown"),
52            ResultCode::OoM => write!(f, "Out of Memory"),
53            ResultCode::Corrupt => write!(f, "Corrupt"),
54            ResultCode::NotFound => write!(f, "Not Found"),
55            ResultCode::AlreadyExists => write!(f, "Already Exists"),
56            ResultCode::PermissionDenied => write!(f, "Permission Denied"),
57            ResultCode::Aborted => write!(f, "Aborted"),
58            ResultCode::OutOfRange => write!(f, "Out of Range"),
59            ResultCode::Unimplemented => write!(f, "Unimplemented"),
60            ResultCode::Internal => write!(f, "Internal Error"),
61            ResultCode::Unavailable => write!(f, "Unavailable"),
62            ResultCode::CustomError => write!(f, "Error "),
63            ResultCode::EOF => write!(f, "EOF"),
64            ResultCode::ReadOnly => write!(f, "Read Only"),
65            ResultCode::RowID => write!(f, "RowID"),
66            ResultCode::Row => write!(f, "Row"),
67            ResultCode::Interrupt => write!(f, "Interrupt"),
68            ResultCode::Busy => write!(f, "Busy"),
69        }
70    }
71}
72#[repr(C)]
73#[derive(PartialEq, Debug, Eq, Clone, Copy)]
74/// StepResult is used to represent the state of a query as it is exposed
75/// to the public API of a connection in a virtual table extension.
76/// the IO variant is always handled internally and therefore is not included here.
77pub enum StepResult {
78    Error,
79    Row,
80    Done,
81    Interrupt,
82    Busy,
83}
84
85impl From<ResultCode> for StepResult {
86    fn from(code: ResultCode) -> Self {
87        match code {
88            ResultCode::Error => StepResult::Error,
89            ResultCode::Row => StepResult::Row,
90            ResultCode::EOF => StepResult::Done,
91            ResultCode::Interrupt => StepResult::Interrupt,
92            ResultCode::Busy => StepResult::Busy,
93            _ => StepResult::Error,
94        }
95    }
96}
97
98#[repr(C)]
99#[derive(PartialEq, Debug, Eq, Clone, Copy)]
100pub enum ValueType {
101    Null,
102    Integer,
103    Float,
104    Text,
105    Blob,
106    Error,
107}
108
109#[repr(C)]
110pub struct Value {
111    value_type: ValueType,
112    value: ValueData,
113}
114impl Default for Value {
115    fn default() -> Self {
116        Self::null()
117    }
118}
119
120#[repr(C)]
121union ValueData {
122    int: i64,
123    float: f64,
124    text: *const TextValue,
125    blob: *const Blob,
126    error: *const ErrValue,
127}
128
129#[repr(C)]
130#[derive(PartialEq, Clone, Copy, Debug)]
131enum TextSubtype {
132    Text,
133    Json,
134}
135
136impl std::fmt::Debug for Value {
137    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138        match self.value_type {
139            ValueType::Null => write!(f, "Value {{ Null }}"),
140            ValueType::Integer => write!(
141                f,
142                "Value {{ Integer: {} }}",
143                self.to_integer().unwrap_or_default()
144            ),
145            ValueType::Float => write!(
146                f,
147                "Value {{ Float: {} }}",
148                self.to_float().unwrap_or_default()
149            ),
150            ValueType::Text => write!(f, "Value {{ Text: {:?} }}", self.to_text()),
151            ValueType::Blob => write!(f, "Value {{ Blob: {:?} }}", self.to_blob()),
152            ValueType::Error => write!(f, "Value {{ Error }}"),
153        }
154    }
155}
156
157#[repr(C)]
158pub struct TextValue {
159    _type: TextSubtype,
160    text: *const u8,
161    len: u32,
162}
163
164impl std::fmt::Debug for TextValue {
165    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166        write!(
167            f,
168            "TextValue {{ text: {:?}, len: {} }}",
169            self.text, self.len
170        )
171    }
172}
173
174impl Default for TextValue {
175    fn default() -> Self {
176        Self {
177            _type: TextSubtype::Text,
178            text: std::ptr::null(),
179            len: 0,
180        }
181    }
182}
183
184impl TextValue {
185    fn new(text: *const u8, len: usize) -> Self {
186        Self {
187            _type: TextSubtype::Text,
188            text,
189            len: len as u32,
190        }
191    }
192
193    fn new_boxed(s: String, sub: TextSubtype) -> Box<Self> {
194        let len = s.len();
195        let buffer = s.into_boxed_str();
196        let strbox = Box::into_raw(buffer);
197        Box::new(Self {
198            _type: sub,
199            text: strbox as *const u8,
200            len: len as u32,
201        })
202    }
203
204    #[cfg(feature = "core_only")]
205    fn free(self) {
206        if !self.text.is_null() {
207            let _ = unsafe { Box::from_raw(self.text as *mut u8) };
208        }
209    }
210
211    fn as_str(&self) -> &str {
212        if self.text.is_null() {
213            return "";
214        }
215        unsafe {
216            std::str::from_utf8_unchecked(std::slice::from_raw_parts(self.text, self.len as usize))
217        }
218    }
219}
220
221#[repr(C)]
222struct ErrValue {
223    code: ResultCode,
224    message: *mut TextValue,
225}
226
227impl ErrValue {
228    fn new(code: ResultCode) -> Self {
229        Self {
230            code,
231            message: std::ptr::null_mut(),
232        }
233    }
234
235    fn new_with_message(code: ResultCode, message: String) -> Self {
236        let buffer = message.into_boxed_str();
237        let ptr = buffer.as_ptr();
238        let len = buffer.len();
239        std::mem::forget(buffer);
240        let text_value = TextValue::new(ptr, len);
241        Self {
242            code,
243            message: Box::into_raw(Box::new(text_value)),
244        }
245    }
246}
247
248#[repr(C)]
249struct Blob {
250    data: *const u8,
251    size: u64,
252}
253
254impl std::fmt::Debug for Blob {
255    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256        write!(f, "Blob {{ data: {:?}, size: {} }}", self.data, self.size)
257    }
258}
259
260impl Blob {
261    pub fn new(data: *const u8, size: u64) -> Self {
262        Self { data, size }
263    }
264
265    pub fn as_bytes(&self) -> &[u8] {
266        if self.data.is_null() {
267            return &[];
268        }
269        unsafe { std::slice::from_raw_parts(self.data, self.size as usize) }
270    }
271    #[cfg(feature = "core_only")]
272    fn free(self) {
273        if !self.data.is_null() {
274            let _ = unsafe { Box::from_raw(self.data as *mut u8) };
275        }
276    }
277}
278
279impl Value {
280    /// Creates a new Value with type Null
281    pub fn null() -> Self {
282        Self {
283            value_type: ValueType::Null,
284            value: ValueData { int: 0 },
285        }
286    }
287
288    /// Returns the value type of the Value
289    pub fn value_type(&self) -> ValueType {
290        self.value_type
291    }
292
293    /// Returns the float value or casts the relevant value to a float
294    pub fn to_float(&self) -> Option<f64> {
295        match self.value_type {
296            ValueType::Float => Some(unsafe { self.value.float }),
297            ValueType::Integer => Some(unsafe { self.value.int } as f64),
298            ValueType::Text => {
299                let txt = self.to_text().unwrap_or_default();
300                txt.parse().ok()
301            }
302            _ => None,
303        }
304    }
305
306    /// Returns the text value if the Value is the proper type
307    pub fn to_text(&self) -> Option<&str> {
308        unsafe {
309            if self.value_type == ValueType::Text && !self.value.text.is_null() {
310                let txt = &*self.value.text;
311                Some(txt.as_str())
312            } else {
313                None
314            }
315        }
316    }
317
318    pub fn is_json(&self) -> bool {
319        unsafe {
320            if self.value_type == ValueType::Text && !self.value.text.is_null() {
321                let txt = &*self.value.text;
322                return txt._type == TextSubtype::Json;
323            }
324        }
325        false
326    }
327
328    /// Returns the blob value if the ValueType is Blob
329    pub fn to_blob(&self) -> Option<Vec<u8>> {
330        match self.value_type {
331            ValueType::Blob => {
332                if unsafe { self.value.blob.is_null() } {
333                    return None;
334                }
335                let blob = unsafe { &*(self.value.blob) };
336                let slice = unsafe { std::slice::from_raw_parts(blob.data, blob.size as usize) };
337                Some(slice.to_vec())
338            }
339            ValueType::Text => {
340                let txt = self.to_text().unwrap_or_default();
341                Some(txt.as_bytes().to_vec())
342            }
343            _ => None,
344        }
345    }
346
347    /// Returns the value as an integer (casts or converts if possible)
348    pub fn to_integer(&self) -> Option<i64> {
349        match self.value_type() {
350            ValueType::Integer => Some(unsafe { self.value.int }),
351            ValueType::Float => Some(unsafe { self.value.float } as i64),
352            ValueType::Text => self
353                .to_text()
354                .map(|txt| txt.parse::<i64>().unwrap_or_default()),
355            _ => None,
356        }
357    }
358
359    /// Returns the error code if the value is an error
360    pub fn to_error(&self) -> Option<ResultCode> {
361        if self.value_type != ValueType::Error {
362            return None;
363        }
364        if unsafe { self.value.error.is_null() } {
365            return None;
366        }
367        let err = unsafe { &*self.value.error };
368        Some(err.code)
369    }
370
371    /// Returns the error code and optional message if the value is an error
372    pub fn to_error_details(&self) -> Option<(ResultCode, Option<String>)> {
373        if self.value_type != ValueType::Error || unsafe { self.value.error.is_null() } {
374            return None;
375        }
376        let err_val = unsafe { &*(self.value.error) };
377        let code = err_val.code;
378
379        if err_val.message.is_null() {
380            Some((code, None))
381        } else {
382            let txt = unsafe { &*(err_val.message as *const TextValue) };
383            let msg = txt.as_str().to_owned();
384            Some((code, Some(msg)))
385        }
386    }
387
388    // Return ValueData as raw bytes
389    pub fn as_bytes(&self) -> Vec<u8> {
390        let mut bytes = vec![];
391        unsafe {
392            match self.value_type {
393                ValueType::Integer => bytes.extend_from_slice(&self.value.int.to_le_bytes()),
394                ValueType::Float => bytes.extend_from_slice(&self.value.float.to_le_bytes()),
395                ValueType::Text => {
396                    let text = self.value.text.as_ref().expect("Invalid text pointer");
397                    bytes.extend_from_slice(text.as_str().as_bytes());
398                }
399                ValueType::Blob => {
400                    let blob = self.value.blob.as_ref().expect("Invalid blob pointer");
401                    bytes.extend_from_slice(blob.as_bytes());
402                }
403                ValueType::Error | ValueType::Null => {}
404            }
405        }
406
407        bytes
408    }
409
410    /// Creates a new integer Value from an i64
411    pub fn from_integer(i: i64) -> Self {
412        Self {
413            value_type: ValueType::Integer,
414            value: ValueData { int: i },
415        }
416    }
417
418    /// Creates a new float Value from a f64
419    pub fn from_float(value: f64) -> Self {
420        Self {
421            value_type: ValueType::Float,
422            value: ValueData { float: value },
423        }
424    }
425
426    /// Creates a new text Value from a String
427    pub fn from_text(s: String) -> Self {
428        let txt_value = TextValue::new_boxed(s, TextSubtype::Text);
429        let ptr = Box::into_raw(txt_value);
430        Self {
431            value_type: ValueType::Text,
432            value: ValueData { text: ptr },
433        }
434    }
435
436    pub fn from_json(s: String) -> Self {
437        let txt_value = TextValue::new_boxed(s, TextSubtype::Json);
438        let ptr = Box::into_raw(txt_value);
439        Self {
440            value_type: ValueType::Text,
441            value: ValueData { text: ptr },
442        }
443    }
444
445    /// Creates a new error Value from a ResultCode
446    pub fn error(code: ResultCode) -> Self {
447        let err_val = ErrValue::new(code);
448        Self {
449            value_type: ValueType::Error,
450            value: ValueData {
451                error: Box::into_raw(Box::new(err_val)) as *const ErrValue,
452            },
453        }
454    }
455
456    /// Creates a new error Value from a ResultCode and a message
457    pub fn error_with_message(message: String) -> Self {
458        let err_value = ErrValue::new_with_message(ResultCode::CustomError, message);
459        let err_box = Box::new(err_value);
460        Self {
461            value_type: ValueType::Error,
462            value: ValueData {
463                error: Box::into_raw(err_box) as *const ErrValue,
464            },
465        }
466    }
467
468    /// Creates a new blob Value from a `Vec<u8>`
469    pub fn from_blob(value: Vec<u8>) -> Self {
470        let len = value.len();
471        let boxed_data = value.into_boxed_slice();
472        let ptr = Box::into_raw(boxed_data) as *const u8;
473        let boxed_blob = Box::new(Blob::new(ptr, len as u64));
474        Self {
475            value_type: ValueType::Blob,
476            value: ValueData {
477                blob: Box::into_raw(boxed_blob) as *const Blob,
478            },
479        }
480    }
481
482    /// Extension authors should __not__ use this function, or enable the 'core_only' feature
483    ///
484    /// # Safety
485    /// consumes the value while freeing the underlying memory with null check.
486    /// however this does assume that the type was properly constructed with
487    /// the appropriate value_type and value.
488    #[cfg(feature = "core_only")]
489    pub unsafe fn __free_internal_type(self) {
490        match self.value_type {
491            ValueType::Text => {
492                let txt = Box::from_raw(self.value.text as *mut TextValue);
493                txt.free();
494            }
495            ValueType::Blob => {
496                let blob = Box::from_raw(self.value.blob as *mut Blob);
497                blob.free();
498            }
499            ValueType::Error => {
500                let err_val = Box::from_raw(self.value.error as *mut ErrValue);
501                if !err_val.message.is_null() {
502                    let _ = Box::from_raw(err_val.message);
503                }
504            }
505            _ => {}
506        }
507    }
508}