use alloc::borrow::Cow;
use alloc::string::String;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use crate::de::{Deserialize, Sink, SinkHandle};
use crate::error::Error;
use crate::event::Atom;
use crate::state::State;
#[repr(transparent)]
pub struct Slot<T, A = T> {
value: Option<T>,
_marker: PhantomData<fn() -> A>,
}
impl<T, A> Slot<T, A> {
#[inline(always)]
pub fn wrap(out: &mut Option<T>) -> &mut Slot<T, A> {
unsafe { &mut *(out as *mut Option<T> as *mut Slot<T, A>) }
}
#[inline(always)]
pub fn set(&mut self, value: T) {
self.value = Some(value);
}
}
impl<'de, T: Send, A: Deserialize<'de, T>> Slot<T, A> {
#[inline(always)]
pub(crate) fn handle<'a>(out: &'a mut Option<T>) -> SinkHandle<'a, 'de> {
let sink: *mut (dyn Sink<'de> + '_) = out as *mut Option<T> as *mut Slot<T, A>;
SinkHandle::to(unsafe {
&mut *core::mem::transmute::<*mut (dyn Sink<'de> + '_), *mut (dyn Sink<'de> + 'a)>(sink)
})
}
}
impl<T, A> Deref for Slot<T, A> {
type Target = Option<T>;
#[inline(always)]
fn deref(&self) -> &Option<T> {
&self.value
}
}
impl<T, A> DerefMut for Slot<T, A> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Option<T> {
&mut self.value
}
}
impl<'de, T: Send, A: Deserialize<'de, T>> Sink<'de> for Slot<T, A> {
#[inline]
fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
A::deserialize_atom(self, atom, state)
}
#[inline]
fn borrowed_atom(&mut self, atom: Atom<'de>, state: &mut State) -> Result<(), Error> {
A::deserialize_borrowed_atom(self, atom, state)
}
fn expecting(&self) -> Cow<'_, str> {
A::expecting()
}
}
pub(crate) fn short_type_name(name: &'static str) -> Cow<'static, str> {
if !name.contains("::") {
return Cow::Borrowed(name);
}
let mut rv = String::with_capacity(name.len());
let mut ident_start = 0;
let mut rest = name;
while let Some(c) = rest.chars().next() {
if let Some(after) = rest.strip_prefix("::") {
rv.truncate(ident_start);
rest = after;
continue;
}
rv.push(c);
if !(c.is_alphanumeric() || c == '_') {
ident_start = rv.len();
}
rest = &rest[c.len_utf8()..];
}
Cow::Owned(rv)
}
#[cfg(test)]
mod tests {
use super::short_type_name;
#[test]
fn test_short_type_name() {
assert_eq!(short_type_name("u32"), "u32");
assert_eq!(short_type_name("my_crate::Point"), "Point");
assert_eq!(
short_type_name("alloc::vec::Vec<my_crate::geo::Point>"),
"Vec<Point>"
);
assert_eq!(
short_type_name("(u8, &alloc::string::String, [a::B; 2])"),
"(u8, &String, [B; 2])"
);
assert_eq!(
short_type_name(
"core::option::Option<std::collections::hash::map::HashMap<a::K, b::V>>"
),
"Option<HashMap<K, V>>"
);
}
}