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