Skip to main content

limbo/
value.rs

1use std::str::FromStr;
2
3use crate::{Error, Result};
4
5#[derive(Clone, Debug, PartialEq)]
6pub enum Value {
7    Null,
8    Integer(i64),
9    Real(f64),
10    Text(String),
11    Blob(Vec<u8>),
12}
13
14/// The possible types a column can be in libsql.
15#[derive(Debug, Copy, Clone)]
16pub enum ValueType {
17    Integer = 1,
18    Real,
19    Text,
20    Blob,
21    Null,
22}
23
24impl FromStr for ValueType {
25    type Err = ();
26
27    fn from_str(s: &str) -> std::result::Result<ValueType, Self::Err> {
28        match s {
29            "TEXT" => Ok(ValueType::Text),
30            "INTEGER" => Ok(ValueType::Integer),
31            "BLOB" => Ok(ValueType::Blob),
32            "NULL" => Ok(ValueType::Null),
33            "REAL" => Ok(ValueType::Real),
34            _ => Err(()),
35        }
36    }
37}
38
39impl Value {
40    /// Returns `true` if the value is [`Null`].
41    ///
42    /// [`Null`]: Value::Null
43    #[must_use]
44    pub fn is_null(&self) -> bool {
45        matches!(self, Self::Null)
46    }
47
48    /// Returns `true` if the value is [`Integer`].
49    ///
50    /// [`Integer`]: Value::Integer
51    #[must_use]
52    pub fn is_integer(&self) -> bool {
53        matches!(self, Self::Integer(..))
54    }
55
56    /// Returns `true` if the value is [`Real`].
57    ///
58    /// [`Real`]: Value::Real
59    #[must_use]
60    pub fn is_real(&self) -> bool {
61        matches!(self, Self::Real(..))
62    }
63
64    pub fn as_real(&self) -> Option<&f64> {
65        if let Self::Real(v) = self {
66            Some(v)
67        } else {
68            None
69        }
70    }
71
72    /// Returns `true` if the value is [`Text`].
73    ///
74    /// [`Text`]: Value::Text
75    #[must_use]
76    pub fn is_text(&self) -> bool {
77        matches!(self, Self::Text(..))
78    }
79
80    pub fn as_text(&self) -> Option<&String> {
81        if let Self::Text(v) = self {
82            Some(v)
83        } else {
84            None
85        }
86    }
87
88    pub fn as_integer(&self) -> Option<&i64> {
89        if let Self::Integer(v) = self {
90            Some(v)
91        } else {
92            None
93        }
94    }
95
96    /// Returns `true` if the value is [`Blob`].
97    ///
98    /// [`Blob`]: Value::Blob
99    #[must_use]
100    pub fn is_blob(&self) -> bool {
101        matches!(self, Self::Blob(..))
102    }
103
104    pub fn as_blob(&self) -> Option<&Vec<u8>> {
105        if let Self::Blob(v) = self {
106            Some(v)
107        } else {
108            None
109        }
110    }
111}
112
113impl Into<limbo_core::Value> for Value {
114    fn into(self) -> limbo_core::Value {
115        match self {
116            Value::Null => limbo_core::Value::Null,
117            Value::Integer(n) => limbo_core::Value::Integer(n),
118            Value::Real(n) => limbo_core::Value::Float(n),
119            Value::Text(t) => limbo_core::Value::from_text(&t),
120            Value::Blob(items) => limbo_core::Value::from_blob(items),
121        }
122    }
123}
124
125impl From<i8> for Value {
126    fn from(value: i8) -> Value {
127        Value::Integer(value as i64)
128    }
129}
130
131impl From<i16> for Value {
132    fn from(value: i16) -> Value {
133        Value::Integer(value as i64)
134    }
135}
136
137impl From<i32> for Value {
138    fn from(value: i32) -> Value {
139        Value::Integer(value as i64)
140    }
141}
142
143impl From<i64> for Value {
144    fn from(value: i64) -> Value {
145        Value::Integer(value)
146    }
147}
148
149impl From<u8> for Value {
150    fn from(value: u8) -> Value {
151        Value::Integer(value as i64)
152    }
153}
154
155impl From<u16> for Value {
156    fn from(value: u16) -> Value {
157        Value::Integer(value as i64)
158    }
159}
160
161impl From<u32> for Value {
162    fn from(value: u32) -> Value {
163        Value::Integer(value as i64)
164    }
165}
166
167impl TryFrom<u64> for Value {
168    type Error = Error;
169
170    fn try_from(value: u64) -> Result<Value> {
171        if value > i64::MAX as u64 {
172            Err(Error::ToSqlConversionFailure(
173                "u64 is too large to fit in an i64".into(),
174            ))
175        } else {
176            Ok(Value::Integer(value as i64))
177        }
178    }
179}
180
181impl From<f32> for Value {
182    fn from(value: f32) -> Value {
183        Value::Real(value as f64)
184    }
185}
186
187impl From<f64> for Value {
188    fn from(value: f64) -> Value {
189        Value::Real(value)
190    }
191}
192
193impl From<&str> for Value {
194    fn from(value: &str) -> Value {
195        Value::Text(value.to_owned())
196    }
197}
198
199impl From<String> for Value {
200    fn from(value: String) -> Value {
201        Value::Text(value)
202    }
203}
204
205impl From<&[u8]> for Value {
206    fn from(value: &[u8]) -> Value {
207        Value::Blob(value.to_owned())
208    }
209}
210
211impl From<Vec<u8>> for Value {
212    fn from(value: Vec<u8>) -> Value {
213        Value::Blob(value)
214    }
215}
216
217impl From<bool> for Value {
218    fn from(value: bool) -> Value {
219        Value::Integer(value as i64)
220    }
221}
222
223impl<T> From<Option<T>> for Value
224where
225    T: Into<Value>,
226{
227    fn from(value: Option<T>) -> Self {
228        match value {
229            Some(inner) => inner.into(),
230            None => Value::Null,
231        }
232    }
233}
234
235/// A borrowed version of `Value`.
236#[derive(Debug)]
237pub enum ValueRef<'a> {
238    Null,
239    Integer(i64),
240    Real(f64),
241    Text(&'a [u8]),
242    Blob(&'a [u8]),
243}
244
245impl ValueRef<'_> {
246    pub fn data_type(&self) -> ValueType {
247        match *self {
248            ValueRef::Null => ValueType::Null,
249            ValueRef::Integer(_) => ValueType::Integer,
250            ValueRef::Real(_) => ValueType::Real,
251            ValueRef::Text(_) => ValueType::Text,
252            ValueRef::Blob(_) => ValueType::Blob,
253        }
254    }
255
256    /// Returns `true` if the value ref is [`Null`].
257    ///
258    /// [`Null`]: ValueRef::Null
259    #[must_use]
260    pub fn is_null(&self) -> bool {
261        matches!(self, Self::Null)
262    }
263
264    /// Returns `true` if the value ref is [`Integer`].
265    ///
266    /// [`Integer`]: ValueRef::Integer
267    #[must_use]
268    pub fn is_integer(&self) -> bool {
269        matches!(self, Self::Integer(..))
270    }
271
272    pub fn as_integer(&self) -> Option<&i64> {
273        if let Self::Integer(v) = self {
274            Some(v)
275        } else {
276            None
277        }
278    }
279
280    /// Returns `true` if the value ref is [`Real`].
281    ///
282    /// [`Real`]: ValueRef::Real
283    #[must_use]
284    pub fn is_real(&self) -> bool {
285        matches!(self, Self::Real(..))
286    }
287
288    pub fn as_real(&self) -> Option<&f64> {
289        if let Self::Real(v) = self {
290            Some(v)
291        } else {
292            None
293        }
294    }
295
296    /// Returns `true` if the value ref is [`Text`].
297    ///
298    /// [`Text`]: ValueRef::Text
299    #[must_use]
300    pub fn is_text(&self) -> bool {
301        matches!(self, Self::Text(..))
302    }
303
304    pub fn as_text(&self) -> Option<&[u8]> {
305        if let Self::Text(v) = self {
306            Some(v)
307        } else {
308            None
309        }
310    }
311
312    /// Returns `true` if the value ref is [`Blob`].
313    ///
314    /// [`Blob`]: ValueRef::Blob
315    #[must_use]
316    pub fn is_blob(&self) -> bool {
317        matches!(self, Self::Blob(..))
318    }
319
320    pub fn as_blob(&self) -> Option<&[u8]> {
321        if let Self::Blob(v) = self {
322            Some(v)
323        } else {
324            None
325        }
326    }
327}
328
329impl From<ValueRef<'_>> for Value {
330    fn from(vr: ValueRef<'_>) -> Value {
331        match vr {
332            ValueRef::Null => Value::Null,
333            ValueRef::Integer(i) => Value::Integer(i),
334            ValueRef::Real(r) => Value::Real(r),
335            ValueRef::Text(s) => Value::Text(String::from_utf8_lossy(s).to_string()),
336            ValueRef::Blob(b) => Value::Blob(b.to_vec()),
337        }
338    }
339}
340
341impl<'a> From<&'a str> for ValueRef<'a> {
342    fn from(s: &str) -> ValueRef<'_> {
343        ValueRef::Text(s.as_bytes())
344    }
345}
346
347impl<'a> From<&'a [u8]> for ValueRef<'a> {
348    fn from(s: &[u8]) -> ValueRef<'_> {
349        ValueRef::Blob(s)
350    }
351}
352
353impl<'a> From<&'a Value> for ValueRef<'a> {
354    fn from(v: &'a Value) -> ValueRef<'a> {
355        match *v {
356            Value::Null => ValueRef::Null,
357            Value::Integer(i) => ValueRef::Integer(i),
358            Value::Real(r) => ValueRef::Real(r),
359            Value::Text(ref s) => ValueRef::Text(s.as_bytes()),
360            Value::Blob(ref b) => ValueRef::Blob(b),
361        }
362    }
363}
364
365impl<'a, T> From<Option<T>> for ValueRef<'a>
366where
367    T: Into<ValueRef<'a>>,
368{
369    #[inline]
370    fn from(s: Option<T>) -> ValueRef<'a> {
371        match s {
372            Some(x) => x.into(),
373            None => ValueRef::Null,
374        }
375    }
376}