use std::any::Any;
use std::ptr;
use crate::util::Utf16String;
#[derive(Debug)]
pub struct LiteralValue {
value: Option<Utf16String>,
}
impl PartialEq for LiteralValue {
fn eq(&self, other: &Self) -> bool {
ptr::eq(self, other)
}
}
impl Eq for LiteralValue {}
impl LiteralValue {
#[must_use]
pub const fn new(value: Option<Utf16String>) -> Self {
Self { value }
}
#[must_use]
pub const fn get_value(&self) -> Option<&Utf16String> {
self.value.as_ref()
}
#[must_use]
pub fn unwrap(object: Option<&dyn Any>) -> Option<&dyn Any> {
let object = object?;
if let Some(literal_value) = object.downcast_ref::<Self>() {
literal_value.get_value().map(|value| value as &dyn Any)
} else {
Some(object)
}
}
}
#[cfg(test)]
mod tests {
use std::any::Any;
use std::ptr;
use super::LiteralValue;
use crate::util::Utf16String;
#[test]
fn preserves_nullable_value_and_unwrap_identity() {
let value = Utf16String::from_rust_str("4");
let literal = LiteralValue::new(Some(value.clone()));
assert_eq!(literal.get_value(), Some(&value));
let unwrapped =
LiteralValue::unwrap(Some(&literal as &dyn Any)).expect("non-null literal must unwrap");
assert_eq!(unwrapped.downcast_ref::<Utf16String>(), Some(&value));
assert!(LiteralValue::unwrap(Some(&LiteralValue::new(None) as &dyn Any)).is_none());
assert!(LiteralValue::unwrap(None).is_none());
let other = String::from("other");
let other_object = &other as &dyn Any;
let same = LiteralValue::unwrap(Some(other_object)).expect("other object");
assert!(ptr::eq(same, other_object));
}
}