use std::any::{Any, TypeId};
pub(crate) const POINTER_TAG: *const i8 = c"sqlite3_ext:PassedRef".as_ptr() as _;
#[repr(C)]
pub struct PassedRef<T: 'static> {
type_id: TypeId,
value: T,
}
impl<T: 'static> PassedRef<T> {
pub fn new(value: T) -> PassedRef<T> {
PassedRef {
type_id: value.type_id(),
value,
}
}
pub(crate) fn get(&self) -> Option<&T> {
if TypeId::of::<T>() == self.type_id {
Some(&self.value)
} else {
None
}
}
}
impl<T: 'static> std::fmt::Debug for PassedRef<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
f.debug_struct("PassedRef")
.field("type_id", &self.type_id)
.finish_non_exhaustive()
}
}
#[cfg(all(modern_sqlite, test, feature = "static"))]
mod test {
use crate::test_helpers::prelude::*;
#[test]
fn get_ref() {
let h = TestHelpers::new();
#[derive(PartialEq, Debug)]
struct MyStruct {
s: String,
}
let owned_struct = MyStruct {
s: "input string".to_owned(),
};
h.with_value(PassedRef::new(owned_struct), |val| {
assert_eq!(val.value_type(), ValueType::Null);
assert_eq!(
val.get_ref::<MyStruct>(),
Some(&MyStruct {
s: "input string".to_owned()
})
);
let dbg = format!("{:?}", val);
let redacted = regex::Regex::new(r"TypeId\(.*?\)|TypeId \{ t: .* \}")
.unwrap()
.replace(&dbg, "TypeId(XXX)");
assert_eq!(redacted, "Null(PassedRef { type_id: TypeId(XXX), .. })");
Ok(())
});
}
#[test]
fn invalid_get_ref() {
let h = TestHelpers::new();
h.with_value(PassedRef::new(0i32), |val| {
assert_eq!(val.value_type(), ValueType::Null);
assert_eq!(val.get_ref::<String>(), None);
Ok(())
});
}
#[test]
fn get_mut_ref() {
use std::cell::Cell;
use std::rc::Rc;
let h = TestHelpers::new();
let r = Rc::new(Cell::new(0i32));
h.with_value(PassedRef::new(r.clone()), |val| {
let r = val.get_ref::<Rc<Cell<i32>>>().unwrap();
r.set(2);
Ok(())
});
assert_eq!(r.get(), 2);
}
}