serde_object/
assistant.rs1use {
4 crate::{Object, Visitor},
5 lazy_static::lazy_static,
6 serde::de::{self, DeserializeSeed as _},
7 std::{any::Any, borrow::Cow, marker::PhantomData, sync::Mutex},
8 wyz::Pipe as _,
9};
10
11#[cfg(feature = "assistant-extra")]
12pub mod extra {
13 use {super::VariantKind, linkme::distributed_slice};
14
15 #[distributed_slice]
17 pub static ENUM_VARIANT_ASSISTS: [fn() -> Option<VariantKind>] = [..];
18
19 pub fn enum_variant_hint() -> Option<VariantKind> {
20 for enum_variant_assist in ENUM_VARIANT_ASSISTS.iter() {
26 if let result @ Some(_) = enum_variant_assist() {
27 return result;
28 }
29 }
30 None
31 }
32}
33
34pub enum VariantKind {
35 Unit,
36 Newtype,
37 Tuple(usize),
38 Struct(Cow<'static, [Cow<'static, str>]>),
39}
40
41pub trait EnumAssistant {
42 fn variant_hint<E: de::Error>(&self, variant: &Object) -> Result<VariantKind, E>;
43}
44
45impl<T: EnumAssistant> EnumAssistant for &T {
46 #[inline(always)]
47 fn variant_hint<E: de::Error>(&self, variant: &Object) -> Result<VariantKind, E> {
48 <T as EnumAssistant>::variant_hint(self, variant)
49 }
50}
51
52pub struct Seed<Assistant: EnumAssistant + Clone>(pub Assistant);
53impl<'de, Assistant: EnumAssistant + Clone> de::DeserializeSeed<'de> for Seed<Assistant> {
54 type Value = Object<'de>;
55
56 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
57 where
58 D: de::Deserializer<'de>,
59 {
60 deserializer.deserialize_any(Visitor(self.0))
61 }
62}
63
64pub struct Assisted<'a, Assistant: EnumAssistant + 'static>(Object<'a>, PhantomData<Assistant>);
65lazy_static! {
66 static ref ASSIST_ASSISTANT: Mutex<Option<&'static (dyn Any + Sync)>> = Mutex::default();
67}
68pub fn assist<'a, Assistant: EnumAssistant + Sync + 'static>(
69 assistant: Assistant, deserialize: impl FnOnce() -> Assisted<'a, Assistant>,
71) -> Object<'a> {
72 *ASSIST_ASSISTANT.lock().unwrap() =
73 Some(unsafe { extend_ref(&assistant) as &'static (dyn Any + Sync) });
74 let result = deserialize();
75 ASSIST_ASSISTANT.lock().unwrap().take(); result.0
77}
78
79impl<'de, Assistant: EnumAssistant> de::Deserialize<'de> for Assisted<'de, Assistant> {
80 fn deserialize<D>(
81 deserializer: D,
82 ) -> std::result::Result<Self, <D as serde::de::Deserializer<'de>>::Error>
83 where
84 D: de::Deserializer<'de>,
85 {
86 Ok(Self(
87 Seed(
88 ASSIST_ASSISTANT
89 .lock()
90 .unwrap()
91 .take()
92 .expect("Could not retrieve stored EnumAssistant.")
93 .pipe(|a| Any::downcast_ref::<Assistant>(a))
94 .expect("Received wrong type of assistant."),
95 )
96 .deserialize(deserializer)?,
97 PhantomData,
98 ))
99 }
100}
101
102unsafe fn extend_ref<T>(reference: &'_ T) -> &'static T {
103 std::mem::transmute(reference)
104}