grafbase_sdk/types/
resolver.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{cbor, wit, SdkError};
4
5use super::Error;
6
7/// List of resolver inputs, each containing the relevant response data associated with the
8/// resolved item.
9#[derive(Clone, Copy)]
10pub struct FieldInputs<'a>(pub(crate) &'a [Vec<u8>]);
11
12impl<'a> From<&'a Vec<Vec<u8>>> for FieldInputs<'a> {
13    fn from(inputs: &'a Vec<Vec<u8>>) -> Self {
14        FieldInputs(inputs.as_slice())
15    }
16}
17
18impl std::fmt::Debug for FieldInputs<'_> {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        f.debug_tuple("FieldInputs").finish_non_exhaustive()
21    }
22}
23
24impl<'a> FieldInputs<'a> {
25    /// Number of items to be resolved.
26    #[allow(clippy::len_without_is_empty)] // Never empty.
27    pub fn len(&self) -> usize {
28        self.0.len()
29    }
30
31    /// Deserialize each byte slice in the `FieldInputs` to a collection of items.
32    pub fn deserialize<T>(&self) -> Result<Vec<T>, SdkError>
33    where
34        T: Deserialize<'a>,
35    {
36        self.0
37            .iter()
38            .map(|input| cbor::from_slice(input).map_err(Into::into))
39            .collect()
40    }
41}
42
43impl<'a> IntoIterator for FieldInputs<'a> {
44    type Item = FieldInput<'a>;
45
46    type IntoIter = FieldInputsIterator<'a>;
47
48    fn into_iter(self) -> Self::IntoIter {
49        FieldInputsIterator(self.0.iter().enumerate())
50    }
51}
52
53/// Iterator over the resolver inputs.
54pub struct FieldInputsIterator<'a>(std::iter::Enumerate<std::slice::Iter<'a, Vec<u8>>>);
55
56impl<'a> Iterator for FieldInputsIterator<'a> {
57    type Item = FieldInput<'a>;
58
59    fn next(&mut self) -> Option<Self::Item> {
60        self.0.next().map(|(i, data)| FieldInput { data, ix: i as u32 })
61    }
62}
63
64/// Response data, if any, for an item to resolve.
65#[derive(Clone, Copy)]
66pub struct FieldInput<'a> {
67    data: &'a [u8],
68    ix: u32,
69}
70
71impl std::fmt::Debug for FieldInput<'_> {
72    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73        f.debug_tuple("FieldInput").finish_non_exhaustive()
74    }
75}
76
77impl<'a> FieldInput<'a> {
78    /// Deserialize a resolver input.
79    pub fn deserialize<T>(&self) -> Result<T, SdkError>
80    where
81        T: Deserialize<'a>,
82    {
83        cbor::from_slice(self.data).map_err(Into::into)
84    }
85}
86
87/// Output for a resolver
88pub struct FieldOutputs(wit::FieldOutput);
89
90impl FieldOutputs {
91    /// If your resolver doesn't depend on response data, this function provides a convenient way
92    /// to create a FieldOutput from a single element.
93    pub fn new<T: Serialize>(inputs: FieldInputs<'_>, data: T) -> Result<FieldOutputs, SdkError> {
94        let data = cbor::to_vec(data)?;
95        let outputs = if inputs.len() > 1 {
96            inputs.0.iter().map(|_| Ok(data.clone())).collect()
97        } else {
98            vec![Ok(data)]
99        };
100        Ok(FieldOutputs(wit::FieldOutput { outputs }))
101    }
102
103    /// If your resolver doesn't depend on response data, this function provides a convenient way
104    /// to create a FieldOutput from an error.
105    pub fn error(inputs: FieldInputs<'_>, error: impl Into<Error>) -> FieldOutputs {
106        let error: wit::Error = Into::<Error>::into(error).into();
107        let outputs = if inputs.len() > 1 {
108            inputs.0.iter().map(|_| Err(error.clone())).collect()
109        } else {
110            vec![Err(error)]
111        };
112        FieldOutputs(wit::FieldOutput { outputs })
113    }
114
115    /// Construct a new `FieldOutput` through an accumulator which allows setting the
116    /// output individually for each `FieldInput`.
117    pub fn builder(inputs: FieldInputs<'_>) -> FieldOutputsBuilder {
118        FieldOutputsBuilder {
119            items: vec![Ok(Vec::new()); inputs.len()],
120        }
121    }
122}
123
124/// Accumulator for setting the output individually for each `FieldInput`.
125pub struct FieldOutputsBuilder {
126    items: Vec<Result<Vec<u8>, wit::Error>>,
127}
128
129impl FieldOutputsBuilder {
130    /// Push the output for a given `FieldInput`.
131    pub fn insert<T: Serialize>(&mut self, input: FieldInput<'_>, data: T) -> Result<(), SdkError> {
132        let data = cbor::to_vec(data)?;
133        self.items[input.ix as usize] = Ok(data);
134        Ok(())
135    }
136
137    /// Push an error for a given `FieldInput`.
138    pub fn insert_error(&mut self, input: FieldInput<'_>, error: impl Into<Error>) {
139        self.items[input.ix as usize] = Err(Into::<Error>::into(error).into());
140    }
141
142    /// Build the `FieldOutput`.
143    pub fn build(self) -> FieldOutputs {
144        FieldOutputs(wit::FieldOutput { outputs: self.items })
145    }
146}
147
148impl From<FieldOutputs> for wit::FieldOutput {
149    fn from(value: FieldOutputs) -> Self {
150        value.0
151    }
152}