use crate::{Value, error::EncodeError};
pub trait Encode {
fn encode(&self) -> Result<Value, EncodeError>;
}
pub trait PrimitiveEncode: Encode + Copy + 'static {}
impl PrimitiveEncode for bool {}
impl PrimitiveEncode for i8 {}
impl PrimitiveEncode for i16 {}
impl PrimitiveEncode for i32 {}
impl PrimitiveEncode for i64 {}
impl PrimitiveEncode for u8 {}
impl PrimitiveEncode for u16 {}
impl PrimitiveEncode for u32 {}
impl PrimitiveEncode for f32 {}
impl PrimitiveEncode for f64 {}
impl<T> Encode for Option<T>
where
T: Encode,
{
fn encode(&self) -> Result<Value, EncodeError> {
if let Some(v) = self {
v.encode()
} else {
Ok(Value::Null { type_info: None })
}
}
}
impl<T> Encode for &Option<T>
where
T: Encode,
{
fn encode(&self) -> Result<Value, EncodeError> {
if let Some(v) = self {
v.encode()
} else {
Ok(Value::Null { type_info: None })
}
}
}
pub type Null = Option<bool>;
#[allow(non_upper_case_globals)]
pub const Null: Null = None;
#[cfg(test)]
mod tests {
use super::*;
use crate::Value;
#[test]
fn test_option_some_i32() {
let opt: Option<i32> = Some(42);
let encoded = opt.encode().unwrap();
if let Value::Integer { value, type_info } = encoded {
assert_eq!(value, 42);
assert_eq!(type_info, None);
} else {
panic!("Expected Integer value, got {:?}", encoded);
}
}
#[test]
fn test_option_none_i32() {
let opt: Option<i32> = None;
let encoded = opt.encode().unwrap();
if let Value::Null { type_info } = encoded {
assert_eq!(type_info, None);
} else {
panic!("Expected Null value, got {:?}", encoded);
}
}
#[test]
fn test_option_some_string() {
let opt: Option<String> = Some("hello".to_string());
let encoded = opt.encode().unwrap();
if let Value::Text { value, type_info } = encoded {
assert_eq!(value.as_ref(), b"hello");
assert_eq!(type_info, None);
} else {
panic!("Expected Text value, got {:?}", encoded);
}
}
#[test]
fn test_option_none_string() {
let opt: Option<String> = None;
let encoded = opt.encode().unwrap();
if let Value::Null { type_info } = encoded {
assert_eq!(type_info, None);
} else {
panic!("Expected Null value, got {:?}", encoded);
}
}
#[test]
fn test_option_some_bool() {
let opt: Option<bool> = Some(true);
let encoded = opt.encode().unwrap();
if let Value::Integer { value, type_info } = encoded {
assert_eq!(value, 1);
assert_eq!(type_info, None);
} else {
panic!("Expected Integer value for bool, got {:?}", encoded);
}
}
#[test]
fn test_option_none_bool() {
let opt: Option<bool> = None;
let encoded = opt.encode().unwrap();
if let Value::Null { type_info } = encoded {
assert_eq!(type_info, None);
} else {
panic!("Expected Null value, got {:?}", encoded);
}
}
#[test]
#[allow(clippy::approx_constant)]
fn test_option_some_f64() {
let opt: Option<f64> = Some(3.14);
let encoded = opt.encode().unwrap();
if let Value::Double { value, type_info } = encoded {
assert_eq!(value, 3.14);
assert_eq!(type_info, None);
} else {
panic!("Expected Double value, got {:?}", encoded);
}
}
#[test]
fn test_option_none_f64() {
let opt: Option<f64> = None;
let encoded = opt.encode().unwrap();
if let Value::Null { type_info } = encoded {
assert_eq!(type_info, None);
} else {
panic!("Expected Null value, got {:?}", encoded);
}
}
#[test]
fn test_option_some_str_reference() {
let opt: Option<&str> = Some("world");
let encoded = opt.encode().unwrap();
if let Value::Text { value, type_info } = encoded {
assert_eq!(value.as_ref(), b"world");
assert_eq!(type_info, None);
} else {
panic!("Expected Text value, got {:?}", encoded);
}
}
#[test]
fn test_option_none_str_reference() {
let opt: Option<&str> = None;
let encoded = opt.encode().unwrap();
if let Value::Null { type_info } = encoded {
assert_eq!(type_info, None);
} else {
panic!("Expected Null value, got {:?}", encoded);
}
}
#[test]
fn test_nested_option() {
let opt: Option<Option<i32>> = Some(Some(100));
let encoded = opt.encode().unwrap();
if let Value::Integer { value, type_info } = encoded {
assert_eq!(value, 100);
assert_eq!(type_info, None);
} else {
panic!("Expected Integer value, got {:?}", encoded);
}
}
#[test]
fn test_nested_option_inner_none() {
let opt: Option<Option<i32>> = Some(None);
let encoded = opt.encode().unwrap();
if let Value::Null { type_info } = encoded {
assert_eq!(type_info, None);
} else {
panic!("Expected Null value, got {:?}", encoded);
}
}
#[test]
fn test_nested_option_outer_none() {
let opt: Option<Option<i32>> = None;
let encoded = opt.encode().unwrap();
if let Value::Null { type_info } = encoded {
assert_eq!(type_info, None);
} else {
panic!("Expected Null value, got {:?}", encoded);
}
}
#[test]
fn test_null_constant() {
let encoded = Null.encode().unwrap();
if let Value::Null { type_info } = encoded {
assert_eq!(type_info, None);
} else {
panic!("Expected Null value, got {:?}", encoded);
}
}
#[test]
fn test_null_alias_type() {
let null_val: Null = None;
let encoded = null_val.encode().unwrap();
if let Value::Null { type_info } = encoded {
assert_eq!(type_info, None);
} else {
panic!("Expected Null value, got {:?}", encoded);
}
}
#[test]
fn test_null_reference() {
let encoded = Null.encode().unwrap();
if let Value::Null { type_info } = encoded {
assert_eq!(type_info, None);
} else {
panic!("Expected Null value, got {:?}", encoded);
}
}
}