1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Copyright 2019-2024 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT
use std::fmt::Display;

use serde::{de::Visitor, forward_to_deserialize_any, Deserialize, Deserializer};

/// "Introspection" by tracing a [`Deserialize`] to see if it's [`Option`]-like.
///
/// This allows us to smoothly translate between rust functions that take an optional
/// parameter, and the content descriptors in OpenRPC.
pub trait Optional<'de>: Deserialize<'de> {
    fn optional() -> bool {
        #[derive(Default)]
        struct DummyDeserializer;

        #[derive(thiserror::Error, Debug)]
        #[error("")]
        struct DeserializeOptionWasCalled(bool);

        impl serde::de::Error for DeserializeOptionWasCalled {
            fn custom<T: Display>(_: T) -> Self {
                Self(false)
            }
        }

        impl<'de> Deserializer<'de> for DummyDeserializer {
            type Error = DeserializeOptionWasCalled;

            fn deserialize_any<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Self::Error> {
                Err(DeserializeOptionWasCalled(false))
            }

            fn deserialize_option<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Self::Error> {
                Err(DeserializeOptionWasCalled(true))
            }

            forward_to_deserialize_any! {
                bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
                bytes byte_buf unit unit_struct newtype_struct seq tuple
                tuple_struct map struct enum identifier ignored_any
            }
        }

        let Err(DeserializeOptionWasCalled(optional)) = Self::deserialize(DummyDeserializer) else {
            unreachable!("DummyDeserializer never returns Ok(..)")
        };
        optional
    }
    /// # Panics
    /// - This is only safe to call if [`Optional::optional`] returns `true`.
    fn unwrap_none() -> Self {
        Self::deserialize(serde_json::Value::Null)
            .expect("`null` json values should deserialize to a `None` for option-like types")
    }
}

impl<'de, T> Optional<'de> for T where T: Deserialize<'de> {}