vector_config/
ser.rs

1use serde_json::Value;
2use std::{cell::RefCell, marker::PhantomData};
3
4use serde::{Serialize, Serializer};
5
6use crate::{
7    schema::{SchemaGenerator, SchemaObject},
8    Configurable, GenerateError, Metadata, ToValue,
9};
10
11/// Delegated serialization.
12///
13/// This adapter type lets us delegate the work of serializing an `I` by delegating it to `H`, where
14/// `H` represents some sort of helper type (a la `serde_with`) that takes `I` and serializes it in
15/// a specific way. This is a common pattern for using standard Rust types on the interior (such as
16/// `std::time::Duration`) but (de)serializing them in more friendly/ergonomic forms, like `10s`,
17/// which requires the use of custom (de)serialize functions or types.
18///
19/// Concretely, in the codegen, if a value has no mitigating configuration, we treat it as if it is
20/// already `Serialize`, and use it directly. Otherwise, if specific attributes are in place that
21/// indicate the use of an optional helper type, we construct `Delegated<I, H>` where `H` is the
22/// value passed to `#[serde(with = "...")]`.
23///
24/// Astute readers may realize: "but isn't the value of `with` supposed to be a module path where a
25/// custom `serialize` and/or `deserialize` function exist?", and they would be correct insofar as
26/// that is what the `serde` documentation states. However, that value is used to construct a _path_
27/// to a function to be called, which means that if you simply specify a type that is in scope, and
28/// it has a public function called `serialize` and/or `deserialize`, you end up with a path like
29/// `MyCustomType::serialize`, which is valid, and `serde` and `serde_with` use this fact to support
30/// generating custom types that can be used for (de)serialization.
31///
32/// This means we do some extra work up front to avoid misclassifying usages of `#[serde(with =
33/// "...")]` that are using module paths, and as such, this also means that those usages are not
34/// supported.
35pub struct Delegated<I, H> {
36    input: I,
37    _helper: PhantomData<fn(H)>,
38}
39
40// Adapter implementation for `serde_with` where the helper `H` is able to serialize `I`.
41impl<I, H> Serialize for Delegated<I, serde_with::As<H>>
42where
43    H: serde_with::SerializeAs<I>,
44{
45    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
46    where
47        S: Serializer,
48    {
49        H::serialize_as(&self.input, serializer)
50    }
51}
52
53impl<I, H> From<I> for Delegated<I, serde_with::As<H>>
54where
55    H: serde_with::SerializeAs<I>,
56{
57    fn from(input: I) -> Self {
58        Self {
59            input,
60            _helper: PhantomData,
61        }
62    }
63}
64
65// Passthrough implementation for any `H` which is `Configurable`.
66impl<I, H> Configurable for Delegated<I, H>
67where
68    H: Configurable,
69{
70    fn referenceable_name() -> Option<&'static str> {
71        // Forward to the underlying `H`.
72        H::referenceable_name()
73    }
74
75    fn metadata() -> Metadata {
76        // Forward to the underlying `H`.
77        //
78        // We have to convert from `Metadata` to `Metadata` which erases the default value,
79        // notably, but delegated helpers should never actually have default values, so this is
80        // essentially a no-op.
81        H::metadata().convert()
82    }
83
84    fn validate_metadata(metadata: &Metadata) -> Result<(), GenerateError> {
85        // Forward to the underlying `H`.
86        //
87        // We have to convert from `Metadata` to `Metadata` which erases the default value,
88        // notably, but `serde_with` helpers should never actually have default values, so this is
89        // essentially a no-op.
90        let converted = metadata.convert();
91        H::validate_metadata(&converted)
92    }
93
94    fn generate_schema(gen: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
95        // Forward to the underlying `H`.
96        H::generate_schema(gen)
97    }
98}
99
100impl<I, H> ToValue for Delegated<I, H>
101where
102    H: Configurable,
103    Delegated<I, H>: Serialize,
104{
105    fn to_value(&self) -> Value {
106        serde_json::to_value(self).unwrap()
107    }
108}