use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::hash::{Hash, Hasher};
use super::varint::encode_varint_simple;
#[derive(Debug, Clone)]
pub enum Value<S, B> {
Null,
Integer(i64),
Real(f64),
Text(S),
Blob(B),
}
impl<S: Copy, B: Copy> Copy for Value<S, B> {}
pub(crate) type MaybeValue<S, B> = Option<Value<S, B>>;
impl<S: AsRef<str> + PartialEq, B: AsRef<[u8]> + PartialEq> PartialEq for Value<S, B> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Value::Integer(a), Value::Integer(b)) => a == b,
(Value::Real(a), Value::Real(b)) => a.to_bits() == b.to_bits(),
(Value::Text(a), Value::Text(b)) => a == b,
(Value::Blob(a), Value::Blob(b)) => a == b,
(Value::Null, Value::Null) => true,
_ => false,
}
}
}
impl<S: AsRef<str> + Eq, B: AsRef<[u8]> + Eq> Eq for Value<S, B> {}
impl<S: AsRef<str> + Hash, B: AsRef<[u8]> + Hash> Hash for Value<S, B> {
fn hash<H: Hasher>(&self, state: &mut H) {
core::mem::discriminant(self).hash(state);
match self {
Value::Integer(v) => v.hash(state),
Value::Real(v) => v.to_bits().hash(state),
Value::Text(v) => v.hash(state),
Value::Blob(v) => v.hash(state),
Value::Null => {}
}
}
}
impl<S: AsRef<str>, B: AsRef<[u8]>> From<i64> for Value<S, B> {
#[inline]
fn from(v: i64) -> Self {
Value::Integer(v)
}
}
impl<S: AsRef<str>, B: AsRef<[u8]>> From<i32> for Value<S, B> {
#[inline]
fn from(v: i32) -> Self {
Value::Integer(i64::from(v))
}
}
impl<B: AsRef<[u8]>> From<String> for Value<String, B> {
#[inline]
fn from(v: String) -> Self {
Value::Text(v)
}
}
impl<B: AsRef<[u8]>> From<&str> for Value<String, B> {
#[inline]
fn from(v: &str) -> Self {
Value::Text(v.to_string())
}
}
impl<S: AsRef<str>, B: AsRef<[u8]>> From<f64> for Value<S, B> {
#[inline]
fn from(v: f64) -> Self {
Value::Real(v)
}
}
impl<S: AsRef<str>> From<Vec<u8>> for Value<S, Vec<u8>> {
fn from(v: Vec<u8>) -> Self {
Value::Blob(v)
}
}
impl<S: AsRef<str>> From<&[u8]> for Value<S, Vec<u8>> {
fn from(v: &[u8]) -> Self {
Value::Blob(v.to_vec())
}
}
impl<T: Into<Value<String, Vec<u8>>>> From<Option<T>> for Value<String, Vec<u8>> {
fn from(opt: Option<T>) -> Self {
match opt {
Some(v) => v.into(),
None => Value::Null,
}
}
}
impl<S: AsRef<str>, B: AsRef<[u8]>> Value<S, B> {
pub fn to_owned(&self) -> Value<String, Vec<u8>> {
match self {
Value::Null => Value::Null,
Value::Integer(v) => Value::Integer(*v),
Value::Real(v) => Value::Real(*v),
Value::Text(s) => Value::Text(s.as_ref().to_string()),
Value::Blob(b) => Value::Blob(b.as_ref().to_vec()),
}
}
pub fn as_ref(&self) -> Value<&str, &[u8]> {
match self {
Value::Null => Value::Null,
Value::Integer(v) => Value::Integer(*v),
Value::Real(v) => Value::Real(*v),
Value::Text(s) => Value::Text(s.as_ref()),
Value::Blob(b) => Value::Blob(b.as_ref()),
}
}
}
mod display;
#[inline]
pub(crate) fn encode_undefined(out: &mut Vec<u8>) {
out.push(0x00);
}
pub(crate) fn encode_value<S: AsRef<str>, B: AsRef<[u8]>>(
out: &mut Vec<u8>,
value: Option<&Value<S, B>>,
) {
match value {
None => encode_undefined(out),
Some(v) => encode_defined_value(out, v),
}
}
pub(crate) fn encode_defined_value<S: AsRef<str>, B: AsRef<[u8]>>(
out: &mut Vec<u8>,
value: &Value<S, B>,
) {
match value {
Value::Null => {
out.push(0x05);
}
Value::Integer(v) => {
out.push(0x01);
out.extend(v.to_be_bytes());
}
Value::Real(v) => {
if v.is_nan() {
out.push(0x05); } else {
out.push(0x02);
let normalized = if *v == 0.0 { 0.0 } else { *v };
out.extend(normalized.to_be_bytes());
}
}
Value::Text(s) => {
let s = s.as_ref();
out.push(0x03);
out.extend(encode_varint_simple(s.len() as u64));
out.extend(s.as_bytes());
}
Value::Blob(b) => {
let b = b.as_ref();
out.push(0x04);
out.extend(encode_varint_simple(b.len() as u64));
out.extend(b);
}
}
}
#[must_use]
pub(crate) fn decode_value(data: &[u8]) -> Option<(MaybeValue<String, Vec<u8>>, usize)> {
use super::varint::decode_varint;
if data.is_empty() {
return None;
}
let type_code = data[0];
let data = &data[1..];
match type_code {
0 => {
Some((None, 1))
}
1 => {
if data.len() < 8 {
return None;
}
let v = i64::from_be_bytes([
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
]);
Some((Some(Value::Integer(v)), 9))
}
2 => {
if data.len() < 8 {
return None;
}
let v = f64::from_be_bytes([
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
]);
if v.is_nan() {
Some((Some(Value::Null), 9))
} else {
let normalized = if v == 0.0 { 0.0 } else { v };
Some((Some(Value::Real(normalized)), 9))
}
}
3 => {
let (len, len_bytes) = decode_varint(data)?;
let len = usize::try_from(len).ok()?;
let data = &data[len_bytes..];
if data.len() < len {
return None;
}
let text = String::from_utf8(data[..len].to_vec()).ok()?;
Some((Some(Value::Text(text)), 1 + len_bytes + len))
}
4 => {
let (len, len_bytes) = decode_varint(data)?;
let len = usize::try_from(len).ok()?;
let data = &data[len_bytes..];
if data.len() < len {
return None;
}
Some((Some(Value::Blob(data[..len].to_vec())), 1 + len_bytes + len))
}
5 => {
Some((Some(Value::Null), 1))
}
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
type TestValue = Value<String, Vec<u8>>;
#[test]
fn test_encode_decode_null() {
let mut buf = Vec::new();
encode_value(&mut buf, Some(&TestValue::Null));
let (decoded, len) = decode_value(&buf).unwrap();
assert_eq!(decoded, Some(TestValue::Null));
assert_eq!(len, buf.len());
}
#[test]
fn test_encode_decode_integers() {
for v in [
0,
1,
-1,
127,
-128,
32767,
-32768,
i64::from(i32::MAX),
i64::MAX,
] {
let mut buf = Vec::new();
encode_value(&mut buf, Some(&TestValue::Integer(v)));
let (decoded, len) = decode_value(&buf).unwrap();
assert_eq!(decoded, Some(TestValue::Integer(v)), "Failed for {v}");
assert_eq!(len, buf.len());
assert_eq!(buf.len(), 9, "Integer {v} should be 9 bytes");
}
}
#[test]
fn test_encode_decode_real() {
let mut buf = Vec::new();
encode_value(&mut buf, Some(&TestValue::Real(6.14159)));
let (decoded, len) = decode_value(&buf).unwrap();
assert_eq!(decoded, Some(TestValue::Real(6.14159)));
assert_eq!(len, buf.len());
assert_eq!(buf.len(), 9);
}
#[test]
fn test_encode_decode_text() {
let mut buf = Vec::new();
let ref_value: Value<&str, &[u8]> = Value::Text("hello");
encode_value(&mut buf, Some(&ref_value));
let (decoded, len) = decode_value(&buf).unwrap();
assert_eq!(decoded, Some(TestValue::Text("hello".to_string())));
assert_eq!(len, buf.len());
assert_eq!(buf.len(), 7);
}
#[test]
fn test_encode_decode_blob() {
let mut buf = Vec::new();
let data: &[u8] = &[1, 2, 3, 4, 5];
let ref_value: Value<&str, &[u8]> = Value::Blob(data);
encode_value(&mut buf, Some(&ref_value));
let (decoded, len) = decode_value(&buf).unwrap();
assert_eq!(decoded, Some(TestValue::Blob(vec![1, 2, 3, 4, 5])));
assert_eq!(len, buf.len());
assert_eq!(buf.len(), 7);
}
#[test]
fn test_encode_decode_undefined() {
let mut buf = Vec::new();
encode_value::<String, Vec<u8>>(&mut buf, None);
let (decoded, len) = decode_value(&buf).unwrap();
assert_eq!(decoded, None);
assert_eq!(len, buf.len());
assert_eq!(buf.len(), 1);
}
#[test]
fn test_changeset_encoding_matches_rusqlite() {
let mut buf = Vec::new();
encode_value(&mut buf, Some(&TestValue::Integer(1)));
assert_eq!(
buf,
vec![0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]
);
let mut buf = Vec::new();
encode_value(&mut buf, Some(&TestValue::Integer(100)));
assert_eq!(
buf,
vec![0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64]
);
let mut buf = Vec::new();
let ref_value: Value<&str, &[u8]> = Value::Text("alice");
encode_value(&mut buf, Some(&ref_value));
assert_eq!(buf, vec![0x03, 0x05, b'a', b'l', b'i', b'c', b'e']);
let mut buf = Vec::new();
encode_value(&mut buf, Some(&Value::Null::<&str, &[u8]>));
assert_eq!(buf, vec![0x05]);
}
#[test]
fn test_cross_type_equality() {
let owned: Value<String, Vec<u8>> = Value::Text("hello".to_string());
let borrowed: Value<&str, &[u8]> = Value::Text("hello");
assert_eq!(owned.as_ref(), borrowed);
assert_eq!(borrowed.to_owned(), owned);
let owned_blob: Value<String, Vec<u8>> = Value::Blob(vec![1, 2, 3]);
let data: &[u8] = &[1, 2, 3];
let borrowed_blob: Value<&str, &[u8]> = Value::Blob(data);
assert_eq!(owned_blob.as_ref(), borrowed_blob);
}
#[test]
fn test_to_owned_and_as_ref() {
let owned: Value<String, Vec<u8>> = Value::Text("hello".to_string());
let borrowed = owned.as_ref();
assert_eq!(owned.as_ref(), borrowed);
let back_to_owned = borrowed.to_owned();
assert_eq!(owned, back_to_owned);
}
#[test]
fn test_value_from_impls() {
type V = Value<String, Vec<u8>>;
let v: V = 42i64.into();
assert_eq!(v, Value::Integer(42));
let v: V = 7i32.into();
assert_eq!(v, Value::Integer(7));
let v: V = 3.5f64.into();
assert_eq!(v, Value::Real(3.5));
let v: V = "hello".into();
assert_eq!(v, Value::Text("hello".into()));
let v: V = String::from("world").into();
assert_eq!(v, Value::Text("world".into()));
let v: V = vec![1u8, 2, 3].into();
assert_eq!(v, Value::Blob(vec![1, 2, 3]));
let slice: &[u8] = &[4, 5, 6];
let v: V = slice.into();
assert_eq!(v, Value::Blob(vec![4, 5, 6]));
let v: V = Some(99i64).into();
assert_eq!(v, Value::Integer(99));
let v: V = None::<i64>.into();
assert_eq!(v, Value::Null);
}
}