use crate::{identifier::Identifier, parse::ParseErrorKind, prelude_internal::*};
use num_bigint::BigInt;
pub trait ParseObjectKey<'doc>: Sized + Eq + core::hash::Hash + Ord {
fn from_object_key(key: &'doc ObjectKey) -> Result<Self, ParseErrorKind>;
fn from_extension_ident(ident: &Identifier) -> Result<Self, ParseErrorKind>;
}
impl<'doc> ParseObjectKey<'doc> for &'doc ObjectKey {
fn from_object_key(key: &'doc ObjectKey) -> Result<Self, ParseErrorKind> {
Ok(key)
}
fn from_extension_ident(_ident: &Identifier) -> Result<Self, ParseErrorKind> {
Err(ParseErrorKind::TypeMismatch {
expected: crate::value::ValueKind::Map,
actual: crate::value::ValueKind::Text,
})
}
}
impl ParseObjectKey<'_> for ObjectKey {
fn from_object_key(key: &ObjectKey) -> Result<Self, ParseErrorKind> {
Ok(key.clone())
}
fn from_extension_ident(ident: &Identifier) -> Result<Self, ParseErrorKind> {
Ok(ObjectKey::String(ident.as_ref().to_string()))
}
}
impl ParseObjectKey<'_> for bool {
fn from_object_key(key: &ObjectKey) -> Result<Self, ParseErrorKind> {
match key {
ObjectKey::String(s) if s == "true" => Ok(true),
ObjectKey::String(s) if s == "false" => Ok(false),
_ => Err(ParseErrorKind::TypeMismatch {
expected: crate::value::ValueKind::Bool,
actual: key_to_value_kind(key),
}),
}
}
fn from_extension_ident(ident: &Identifier) -> Result<Self, ParseErrorKind> {
match ident.as_ref() {
"true" => Ok(true),
"false" => Ok(false),
_ => Err(ParseErrorKind::TypeMismatch {
expected: crate::value::ValueKind::Bool,
actual: crate::value::ValueKind::Text,
}),
}
}
}
impl ParseObjectKey<'_> for BigInt {
fn from_object_key(key: &ObjectKey) -> Result<Self, ParseErrorKind> {
match key {
ObjectKey::Number(n) => Ok(n.clone()),
_ => Err(ParseErrorKind::TypeMismatch {
expected: crate::value::ValueKind::Integer,
actual: key_to_value_kind(key),
}),
}
}
fn from_extension_ident(_ident: &Identifier) -> Result<Self, ParseErrorKind> {
Err(ParseErrorKind::TypeMismatch {
expected: crate::value::ValueKind::Integer,
actual: crate::value::ValueKind::Text,
})
}
}
impl ParseObjectKey<'_> for String {
fn from_object_key(key: &ObjectKey) -> Result<Self, ParseErrorKind> {
match key {
ObjectKey::String(s) => Ok(s.clone()),
_ => Err(ParseErrorKind::TypeMismatch {
expected: crate::value::ValueKind::Text,
actual: key_to_value_kind(key),
}),
}
}
fn from_extension_ident(ident: &Identifier) -> Result<Self, ParseErrorKind> {
Ok(ident.as_ref().to_string())
}
}
fn key_to_value_kind(key: &ObjectKey) -> crate::value::ValueKind {
match key {
ObjectKey::Number(_) => crate::value::ValueKind::Integer,
ObjectKey::String(_) => crate::value::ValueKind::Text,
ObjectKey::Tuple(_) => crate::value::ValueKind::Tuple,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::value::Tuple;
#[test]
fn test_parse_object_key_borrowed() {
let key = ObjectKey::String("test".into());
let borrowed: &ObjectKey = ParseObjectKey::from_object_key(&key).unwrap();
assert_eq!(borrowed, &key);
}
#[test]
fn test_parse_object_key_owned() {
let key = ObjectKey::String("test".into());
let owned: ObjectKey = ParseObjectKey::from_object_key(&key).unwrap();
assert_eq!(owned, key);
}
#[test]
fn test_borrowed_key_is_zero_copy() {
let key = ObjectKey::String("test".into());
let borrowed: &ObjectKey = ParseObjectKey::from_object_key(&key).unwrap();
assert!(core::ptr::eq(&key, borrowed));
}
#[test]
#[allow(clippy::bool_assert_comparison)]
fn test_parse_bool_key() {
let key = ObjectKey::String("true".into());
let b: bool = ParseObjectKey::from_object_key(&key).unwrap();
assert_eq!(b, true);
let key_false = ObjectKey::String("false".into());
let b_false: bool = ParseObjectKey::from_object_key(&key_false).unwrap();
assert_eq!(b_false, false);
}
#[test]
fn test_parse_bool_key_type_mismatch() {
let key = ObjectKey::String("not a bool".into());
let result: Result<bool, _> = ParseObjectKey::from_object_key(&key);
assert!(result.is_err());
}
#[test]
fn test_parse_bigint_key() {
let key = ObjectKey::Number(BigInt::from(42));
let n: BigInt = ParseObjectKey::from_object_key(&key).unwrap();
assert_eq!(n, BigInt::from(42));
}
#[test]
fn test_parse_bigint_key_type_mismatch() {
let key = ObjectKey::String("not a number".into());
let result: Result<BigInt, _> = ParseObjectKey::from_object_key(&key);
assert!(result.is_err());
}
#[test]
fn test_parse_string_key() {
let key = ObjectKey::String("hello".into());
let s: String = ParseObjectKey::from_object_key(&key).unwrap();
assert_eq!(s, "hello");
}
#[test]
fn test_parse_string_key_type_mismatch() {
let key = ObjectKey::Number(BigInt::from(123));
let result: Result<String, _> = ParseObjectKey::from_object_key(&key);
assert!(result.is_err());
}
#[test]
fn test_parse_tuple_key() {
let key = ObjectKey::Tuple(Tuple(vec![
ObjectKey::String("a".into()),
ObjectKey::Number(BigInt::from(1)),
]));
let owned: ObjectKey = ParseObjectKey::from_object_key(&key).unwrap();
assert_eq!(owned, key);
}
}