1use alloc::string::String;
13use alloc::vec::Vec;
14use core::cmp::Ordering;
15
16#[derive(Debug, Clone, PartialEq)]
22pub enum Value {
23 Null,
25 Integer(i64),
27 Real(f64),
29 Text(String),
32 Blob(Vec<u8>),
34}
35
36#[derive(Debug, Clone, Copy, PartialEq)]
38pub enum ValueRef<'a> {
39 Null,
41 Integer(i64),
43 Real(f64),
45 Text(&'a str),
47 Blob(&'a [u8]),
49}
50
51impl ValueRef<'_> {
52 pub fn to_owned(&self) -> Value {
54 match *self {
55 ValueRef::Null => Value::Null,
56 ValueRef::Integer(i) => Value::Integer(i),
57 ValueRef::Real(r) => Value::Real(r),
58 ValueRef::Text(s) => Value::Text(String::from(s)),
59 ValueRef::Blob(b) => Value::Blob(Vec::from(b)),
60 }
61 }
62}
63
64pub fn cmp_values(a: &Value, b: &Value) -> Ordering {
69 fn class(v: &Value) -> u8 {
70 match v {
71 Value::Null => 0,
72 Value::Integer(_) | Value::Real(_) => 1,
73 Value::Text(_) => 2,
74 Value::Blob(_) => 3,
75 }
76 }
77 fn as_f64(v: &Value) -> f64 {
78 match v {
79 Value::Integer(i) => *i as f64,
80 Value::Real(r) => *r,
81 _ => 0.0,
82 }
83 }
84 match (a, b) {
85 (Value::Null, Value::Null) => Ordering::Equal,
86 (Value::Integer(_) | Value::Real(_), Value::Integer(_) | Value::Real(_)) => {
87 as_f64(a).partial_cmp(&as_f64(b)).unwrap_or(Ordering::Equal)
88 }
89 (Value::Text(x), Value::Text(y)) => x.as_bytes().cmp(y.as_bytes()),
90 (Value::Blob(x), Value::Blob(y)) => x.cmp(y),
91 _ => class(a).cmp(&class(b)),
92 }
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116pub struct SerialType(pub u64);
117
118impl SerialType {
119 pub fn content_len(self) -> Option<usize> {
122 Some(match self.0 {
123 0 | 8 | 9 => 0,
124 1 => 1,
125 2 => 2,
126 3 => 3,
127 4 => 4,
128 5 => 6,
129 6 | 7 => 8,
130 10 | 11 => return None,
131 n if n % 2 == 0 => ((n - 12) / 2) as usize,
132 n => ((n - 13) / 2) as usize,
133 })
134 }
135
136 pub fn for_value(value: &Value) -> SerialType {
141 SerialType(match value {
142 Value::Null => 0,
143 Value::Integer(0) => 8,
144 Value::Integer(1) => 9,
145 Value::Integer(i) => {
146 let i = *i;
147 if (-0x80..=0x7f).contains(&i) {
148 1
149 } else if (-0x8000..=0x7fff).contains(&i) {
150 2
151 } else if (-0x80_0000..=0x7f_ffff).contains(&i) {
152 3
153 } else if (-0x8000_0000..=0x7fff_ffff).contains(&i) {
154 4
155 } else if (-0x8000_0000_0000..=0x7fff_ffff_ffff).contains(&i) {
156 5
157 } else {
158 6
159 }
160 }
161 Value::Real(_) => 7,
162 Value::Blob(b) => 12 + 2 * b.len() as u64,
163 Value::Text(s) => 13 + 2 * s.len() as u64,
164 })
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171 use alloc::string::ToString;
172 use alloc::vec;
173
174 #[test]
175 fn content_lengths() {
176 assert_eq!(SerialType(0).content_len(), Some(0));
177 assert_eq!(SerialType(1).content_len(), Some(1));
178 assert_eq!(SerialType(5).content_len(), Some(6));
179 assert_eq!(SerialType(6).content_len(), Some(8));
180 assert_eq!(SerialType(7).content_len(), Some(8));
181 assert_eq!(SerialType(8).content_len(), Some(0));
182 assert_eq!(SerialType(9).content_len(), Some(0));
183 assert_eq!(SerialType(10).content_len(), None);
184 assert_eq!(SerialType(11).content_len(), None);
185 assert_eq!(SerialType(20).content_len(), Some(4));
187 assert_eq!(SerialType(23).content_len(), Some(5));
189 }
190
191 #[test]
192 fn serial_type_selection_matches_sqlite() {
193 assert_eq!(SerialType::for_value(&Value::Null), SerialType(0));
194 assert_eq!(SerialType::for_value(&Value::Integer(0)), SerialType(8));
195 assert_eq!(SerialType::for_value(&Value::Integer(1)), SerialType(9));
196 assert_eq!(SerialType::for_value(&Value::Integer(2)), SerialType(1));
197 assert_eq!(SerialType::for_value(&Value::Integer(127)), SerialType(1));
198 assert_eq!(SerialType::for_value(&Value::Integer(128)), SerialType(2));
199 assert_eq!(SerialType::for_value(&Value::Integer(-1)), SerialType(1));
200 assert_eq!(
201 SerialType::for_value(&Value::Integer(i64::MAX)),
202 SerialType(6)
203 );
204 assert_eq!(SerialType::for_value(&Value::Real(1.5)), SerialType(7));
205 assert_eq!(
206 SerialType::for_value(&Value::Text("abc".to_string())),
207 SerialType(19) );
209 assert_eq!(
210 SerialType::for_value(&Value::Blob(vec![0u8; 4])),
211 SerialType(20) );
213 }
214
215 #[test]
216 fn value_ref_round_trips() {
217 assert_eq!(ValueRef::Integer(5).to_owned(), Value::Integer(5));
218 assert_eq!(ValueRef::Text("x").to_owned(), Value::Text("x".to_string()));
219 }
220}