Skip to main content

icu_provider/buf/
serde.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5//! Provides the [`DeserializingBufferProvider`] wrapper, which deserializes data using Serde.
6//!
7//! Providers that produce opaque buffers that need to be deserialized into concrete data structs,
8//! such as `FsDataProvider`, should implement [`BufferProvider`]. These can be converted into
9//! [`DeserializingBufferProvider`] using the [`as_deserializing`](AsDeserializingBufferProvider::as_deserializing)
10//! convenience method.
11//!
12//! [`BufferProvider`]: crate::buf::BufferProvider
13
14use crate::DryDataProvider;
15use crate::buf::BufferFormat;
16use crate::buf::BufferProvider;
17use crate::data_provider::DynamicDryDataProvider;
18use crate::prelude::*;
19use serde::de::Deserialize;
20use yoke::Yokeable;
21
22/// A [`BufferProvider`] that deserializes its data using Serde.
23#[derive(Debug)]
24pub struct DeserializingBufferProvider<'a, P: ?Sized>(&'a P);
25
26/// Blanket-implemented trait adding the [`Self::as_deserializing()`] function.
27///
28/// ✨ *Enabled with the `serde` Cargo feature.*
29pub trait AsDeserializingBufferProvider {
30    /// Wrap this [`BufferProvider`] in a [`DeserializingBufferProvider`].
31    ///
32    /// This requires enabling the deserialization Cargo feature
33    /// for the expected format(s):
34    ///
35    /// - `deserialize_json`
36    /// - `deserialize_postcard_1`
37    /// - `deserialize_bincode_1`
38    ///
39    /// ✨ *Enabled with the `serde` Cargo feature.*
40    fn as_deserializing(&self) -> DeserializingBufferProvider<'_, Self>;
41}
42
43impl<P> AsDeserializingBufferProvider for P
44where
45    P: BufferProvider + ?Sized,
46{
47    /// Wrap this [`BufferProvider`] in a [`DeserializingBufferProvider`].
48    ///
49    /// This requires enabling the deserialization Cargo feature
50    /// for the expected format(s):
51    ///
52    /// - `deserialize_json`
53    /// - `deserialize_postcard_1`
54    /// - `deserialize_bincode_1`
55    ///
56    /// ✨ *Enabled with the `serde` Cargo feature.*
57    fn as_deserializing(&self) -> DeserializingBufferProvider<'_, Self> {
58        DeserializingBufferProvider(self)
59    }
60}
61
62fn deserialize_impl<'data, M>(
63    // Allow `bytes` to be unused in case all buffer formats are disabled
64    #[allow(unused_variables)] bytes: &'data [u8],
65    buffer_format: BufferFormat,
66) -> Result<<M::DataStruct as Yokeable<'data>>::Output, DataError>
67where
68    M: DynamicDataMarker,
69    for<'de> <M::DataStruct as Yokeable<'de>>::Output: Deserialize<'de>,
70{
71    match buffer_format {
72        #[cfg(feature = "deserialize_json")]
73        BufferFormat::Json => {
74            let mut d = serde_json::Deserializer::from_slice(bytes);
75            Ok(Deserialize::deserialize(&mut d)?)
76        }
77
78        #[cfg(feature = "deserialize_bincode_1")]
79        BufferFormat::Bincode1 => {
80            use bincode::Options;
81            let options = bincode::DefaultOptions::new()
82                .with_fixint_encoding()
83                .allow_trailing_bytes();
84            let mut d = bincode::de::Deserializer::from_slice(bytes, options);
85            Ok(Deserialize::deserialize(&mut d)?)
86        }
87
88        #[cfg(feature = "deserialize_postcard_1")]
89        BufferFormat::Postcard1 => {
90            let mut d = postcard::Deserializer::from_bytes(bytes);
91            Ok(Deserialize::deserialize(&mut d)?)
92        }
93
94        // Allowed for cases in which all features are enabled
95        #[allow(unreachable_patterns)]
96        _ => {
97            buffer_format.check_available()?;
98            unreachable!()
99        }
100    }
101}
102
103impl DataPayload<BufferMarker> {
104    /// Deserialize a [`DataPayload`]`<`[`BufferMarker`]`>` into a [`DataPayload`] of a
105    /// specific concrete type.
106    ///
107    /// This requires enabling the deserialization Cargo feature
108    /// for the expected format(s):
109    ///
110    /// - `deserialize_json`
111    /// - `deserialize_postcard_1`
112    /// - `deserialize_bincode_1`
113    ///
114    /// This function takes the buffer format as an argument. When a buffer payload is returned
115    /// from a data provider, the buffer format is stored in the [`DataResponseMetadata`].
116    ///
117    /// ✨ *Enabled with the `serde` Cargo feature.*
118    ///
119    /// # Examples
120    ///
121    /// Requires the `deserialize_json` Cargo feature:
122    ///
123    /// ```
124    /// use icu_provider::buf::BufferFormat;
125    /// use icu_provider::hello_world::*;
126    /// use icu_provider::prelude::*;
127    ///
128    /// let buffer: &[u8] = br#"{"message":"Hallo Welt"}"#;
129    ///
130    /// let buffer_payload = DataPayload::from_owned(buffer);
131    /// let payload: DataPayload<HelloWorldV1> = buffer_payload
132    ///     .into_deserialized(BufferFormat::Json)
133    ///     .expect("Deserialization successful");
134    ///
135    /// assert_eq!(payload.get().message, "Hallo Welt");
136    /// ```
137    pub fn into_deserialized<M>(
138        self,
139        buffer_format: BufferFormat,
140    ) -> Result<DataPayload<M>, DataError>
141    where
142        M: DynamicDataMarker,
143        for<'de> <M::DataStruct as Yokeable<'de>>::Output: Deserialize<'de>,
144    {
145        self.try_map_project(|bytes, _| deserialize_impl::<M>(bytes, buffer_format))
146    }
147}
148
149impl<P, M> DynamicDataProvider<M> for DeserializingBufferProvider<'_, P>
150where
151    M: DynamicDataMarker,
152    P: BufferProvider + ?Sized,
153    for<'de> <M::DataStruct as Yokeable<'de>>::Output: Deserialize<'de>,
154{
155    /// Converts a buffer into a concrete type by deserializing from a supported buffer format.
156    ///
157    /// This requires enabling the deserialization Cargo feature
158    /// for the expected format(s):
159    ///
160    /// - `deserialize_json`
161    /// - `deserialize_postcard_1`
162    /// - `deserialize_bincode_1`
163    ///
164    /// ✨ *Enabled with the `serde` Cargo feature.*
165    fn load_data(
166        &self,
167        marker: DataMarkerInfo,
168        req: DataRequest,
169    ) -> Result<DataResponse<M>, DataError> {
170        let buffer_response = self.0.load_data(marker, req)?;
171        let buffer_format = buffer_response.metadata.buffer_format.ok_or_else(|| {
172            DataErrorKind::Deserialize
173                .with_str_context("BufferProvider didn't set BufferFormat")
174                .with_req(marker, req)
175        })?;
176        Ok(DataResponse {
177            metadata: buffer_response.metadata,
178            payload: buffer_response
179                .payload
180                .into_deserialized(buffer_format)
181                .map_err(|e| e.with_req(marker, req))?,
182        })
183    }
184}
185
186impl<P, M> DynamicDryDataProvider<M> for DeserializingBufferProvider<'_, P>
187where
188    M: DynamicDataMarker,
189    P: DynamicDryDataProvider<BufferMarker> + ?Sized,
190    for<'de> <M::DataStruct as Yokeable<'de>>::Output: Deserialize<'de>,
191{
192    fn dry_load_data(
193        &self,
194        marker: DataMarkerInfo,
195        req: DataRequest,
196    ) -> Result<DataResponseMetadata, DataError> {
197        self.0.dry_load_data(marker, req)
198    }
199}
200
201impl<P, M> DataProvider<M> for DeserializingBufferProvider<'_, P>
202where
203    M: DataMarker,
204    P: DynamicDataProvider<BufferMarker> + ?Sized,
205    for<'de> <M::DataStruct as Yokeable<'de>>::Output: Deserialize<'de>,
206{
207    /// Converts a buffer into a concrete type by deserializing from a supported buffer format.
208    ///
209    /// This requires enabling the deserialization Cargo feature
210    /// for the expected format(s):
211    ///
212    /// - `deserialize_json`
213    /// - `deserialize_postcard_1`
214    /// - `deserialize_bincode_1`
215    ///
216    /// ✨ *Enabled with the `serde` Cargo feature.*
217    fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
218        self.load_data(M::INFO, req)
219    }
220}
221
222impl<P, M> DryDataProvider<M> for DeserializingBufferProvider<'_, P>
223where
224    M: DataMarker,
225    P: DynamicDryDataProvider<BufferMarker> + ?Sized,
226    for<'de> <M::DataStruct as Yokeable<'de>>::Output: Deserialize<'de>,
227{
228    fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
229        self.0.dry_load_data(M::INFO, req)
230    }
231}
232
233#[cfg(feature = "deserialize_json")]
234impl From<serde_json::error::Error> for DataError {
235    fn from(e: serde_json::error::Error) -> Self {
236        DataErrorKind::Deserialize
237            .with_str_context("serde_json")
238            .with_display_context(&e)
239    }
240}
241
242#[cfg(feature = "deserialize_bincode_1")]
243impl From<bincode::Error> for DataError {
244    fn from(e: bincode::Error) -> Self {
245        DataErrorKind::Deserialize
246            .with_str_context("bincode")
247            .with_display_context(&e)
248    }
249}
250
251#[cfg(feature = "deserialize_postcard_1")]
252impl From<postcard::Error> for DataError {
253    fn from(e: postcard::Error) -> Self {
254        DataErrorKind::Deserialize
255            .with_str_context("postcard")
256            .with_display_context(&e)
257    }
258}