xref: /aosp_15_r20/external/crosvm/base/src/descriptor_reflection.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2020 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! Provides infrastructure for de/serializing descriptors embedded in Rust data structures.
6*bb4ee6a4SAndroid Build Coastguard Worker //!
7*bb4ee6a4SAndroid Build Coastguard Worker //! # Example
8*bb4ee6a4SAndroid Build Coastguard Worker //!
9*bb4ee6a4SAndroid Build Coastguard Worker //! ```
10*bb4ee6a4SAndroid Build Coastguard Worker //! use serde_json::to_string;
11*bb4ee6a4SAndroid Build Coastguard Worker //! use base::{
12*bb4ee6a4SAndroid Build Coastguard Worker //!     FileSerdeWrapper, FromRawDescriptor, SafeDescriptor, SerializeDescriptors,
13*bb4ee6a4SAndroid Build Coastguard Worker //!     deserialize_with_descriptors,
14*bb4ee6a4SAndroid Build Coastguard Worker //! };
15*bb4ee6a4SAndroid Build Coastguard Worker //! use tempfile::tempfile;
16*bb4ee6a4SAndroid Build Coastguard Worker //!
17*bb4ee6a4SAndroid Build Coastguard Worker //! let tmp_f = tempfile().unwrap();
18*bb4ee6a4SAndroid Build Coastguard Worker //!
19*bb4ee6a4SAndroid Build Coastguard Worker //! // Uses a simple wrapper to serialize a File because we can't implement Serialize for File.
20*bb4ee6a4SAndroid Build Coastguard Worker //! let data = FileSerdeWrapper(tmp_f);
21*bb4ee6a4SAndroid Build Coastguard Worker //!
22*bb4ee6a4SAndroid Build Coastguard Worker //! // Wraps Serialize types to collect side channel descriptors as Serialize is called.
23*bb4ee6a4SAndroid Build Coastguard Worker //! let data_wrapper = SerializeDescriptors::new(&data);
24*bb4ee6a4SAndroid Build Coastguard Worker //!
25*bb4ee6a4SAndroid Build Coastguard Worker //! // Use the wrapper with any serializer to serialize data is normal, grabbing descriptors
26*bb4ee6a4SAndroid Build Coastguard Worker //! // as the data structures are serialized by the serializer.
27*bb4ee6a4SAndroid Build Coastguard Worker //! let out_json = serde_json::to_string(&data_wrapper).expect("failed to serialize");
28*bb4ee6a4SAndroid Build Coastguard Worker //!
29*bb4ee6a4SAndroid Build Coastguard Worker //! // If data_wrapper contains any side channel descriptor refs
30*bb4ee6a4SAndroid Build Coastguard Worker //! // (it contains tmp_f in this case), we can retrieve the actual descriptors
31*bb4ee6a4SAndroid Build Coastguard Worker //! // from the side channel using into_descriptors().
32*bb4ee6a4SAndroid Build Coastguard Worker //! let out_descriptors = data_wrapper.into_descriptors();
33*bb4ee6a4SAndroid Build Coastguard Worker //!
34*bb4ee6a4SAndroid Build Coastguard Worker //! // When sending out_json over some transport, also send out_descriptors.
35*bb4ee6a4SAndroid Build Coastguard Worker //!
36*bb4ee6a4SAndroid Build Coastguard Worker //! // For this example, we aren't really transporting data across the process, but we do need to
37*bb4ee6a4SAndroid Build Coastguard Worker //! // convert the descriptor type.
38*bb4ee6a4SAndroid Build Coastguard Worker //! let mut safe_descriptors = out_descriptors
39*bb4ee6a4SAndroid Build Coastguard Worker //!     .iter()
40*bb4ee6a4SAndroid Build Coastguard Worker //!     .map(|&v| unsafe { SafeDescriptor::from_raw_descriptor(v) });
41*bb4ee6a4SAndroid Build Coastguard Worker //! std::mem::forget(data); // Prevent double drop of tmp_f.
42*bb4ee6a4SAndroid Build Coastguard Worker //!
43*bb4ee6a4SAndroid Build Coastguard Worker //! // The deserialize_with_descriptors function is used give the descriptor deserializers access
44*bb4ee6a4SAndroid Build Coastguard Worker //! // to side channel descriptors.
45*bb4ee6a4SAndroid Build Coastguard Worker //! let res: FileSerdeWrapper =
46*bb4ee6a4SAndroid Build Coastguard Worker //!     deserialize_with_descriptors(|| serde_json::from_str(&out_json), safe_descriptors)
47*bb4ee6a4SAndroid Build Coastguard Worker //!        .expect("failed to deserialize");
48*bb4ee6a4SAndroid Build Coastguard Worker //! ```
49*bb4ee6a4SAndroid Build Coastguard Worker 
50*bb4ee6a4SAndroid Build Coastguard Worker use std::cell::Cell;
51*bb4ee6a4SAndroid Build Coastguard Worker use std::cell::RefCell;
52*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryInto;
53*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt;
54*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
55*bb4ee6a4SAndroid Build Coastguard Worker use std::ops::Deref;
56*bb4ee6a4SAndroid Build Coastguard Worker use std::ops::DerefMut;
57*bb4ee6a4SAndroid Build Coastguard Worker use std::panic::catch_unwind;
58*bb4ee6a4SAndroid Build Coastguard Worker use std::panic::resume_unwind;
59*bb4ee6a4SAndroid Build Coastguard Worker use std::panic::AssertUnwindSafe;
60*bb4ee6a4SAndroid Build Coastguard Worker 
61*bb4ee6a4SAndroid Build Coastguard Worker use serde::de;
62*bb4ee6a4SAndroid Build Coastguard Worker use serde::de::Error;
63*bb4ee6a4SAndroid Build Coastguard Worker use serde::de::Visitor;
64*bb4ee6a4SAndroid Build Coastguard Worker use serde::ser;
65*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
66*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserializer;
67*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
68*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serializer;
69*bb4ee6a4SAndroid Build Coastguard Worker 
70*bb4ee6a4SAndroid Build Coastguard Worker use super::RawDescriptor;
71*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::SafeDescriptor;
72*bb4ee6a4SAndroid Build Coastguard Worker 
73*bb4ee6a4SAndroid Build Coastguard Worker thread_local! {
74*bb4ee6a4SAndroid Build Coastguard Worker     static DESCRIPTOR_DST: RefCell<Option<Vec<RawDescriptor>>> = Default::default();
75*bb4ee6a4SAndroid Build Coastguard Worker }
76*bb4ee6a4SAndroid Build Coastguard Worker 
77*bb4ee6a4SAndroid Build Coastguard Worker /// Initializes the thread local storage for descriptor serialization. Fails if it was already
78*bb4ee6a4SAndroid Build Coastguard Worker /// initialized without an intervening `take_descriptor_dst` on this thread.
init_descriptor_dst() -> Result<(), &'static str>79*bb4ee6a4SAndroid Build Coastguard Worker fn init_descriptor_dst() -> Result<(), &'static str> {
80*bb4ee6a4SAndroid Build Coastguard Worker     DESCRIPTOR_DST.with(|d| {
81*bb4ee6a4SAndroid Build Coastguard Worker         let mut descriptors = d.borrow_mut();
82*bb4ee6a4SAndroid Build Coastguard Worker         if descriptors.is_some() {
83*bb4ee6a4SAndroid Build Coastguard Worker             return Err(
84*bb4ee6a4SAndroid Build Coastguard Worker                 "attempt to initialize descriptor destination that was already initialized",
85*bb4ee6a4SAndroid Build Coastguard Worker             );
86*bb4ee6a4SAndroid Build Coastguard Worker         }
87*bb4ee6a4SAndroid Build Coastguard Worker         *descriptors = Some(Default::default());
88*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
89*bb4ee6a4SAndroid Build Coastguard Worker     })
90*bb4ee6a4SAndroid Build Coastguard Worker }
91*bb4ee6a4SAndroid Build Coastguard Worker 
92*bb4ee6a4SAndroid Build Coastguard Worker /// Takes the thread local storage for descriptor serialization. Fails if there wasn't a prior call
93*bb4ee6a4SAndroid Build Coastguard Worker /// to `init_descriptor_dst` on this thread.
take_descriptor_dst() -> Result<Vec<RawDescriptor>, &'static str>94*bb4ee6a4SAndroid Build Coastguard Worker fn take_descriptor_dst() -> Result<Vec<RawDescriptor>, &'static str> {
95*bb4ee6a4SAndroid Build Coastguard Worker     match DESCRIPTOR_DST.with(|d| d.replace(None)) {
96*bb4ee6a4SAndroid Build Coastguard Worker         Some(d) => Ok(d),
97*bb4ee6a4SAndroid Build Coastguard Worker         None => Err("attempt to take descriptor destination before it was initialized"),
98*bb4ee6a4SAndroid Build Coastguard Worker     }
99*bb4ee6a4SAndroid Build Coastguard Worker }
100*bb4ee6a4SAndroid Build Coastguard Worker 
101*bb4ee6a4SAndroid Build Coastguard Worker /// Pushes a descriptor on the thread local destination of descriptors, returning the index in which
102*bb4ee6a4SAndroid Build Coastguard Worker /// the descriptor was pushed.
103*bb4ee6a4SAndroid Build Coastguard Worker //
104*bb4ee6a4SAndroid Build Coastguard Worker /// Returns Err if the thread local destination was not already initialized.
push_descriptor(rd: RawDescriptor) -> Result<usize, &'static str>105*bb4ee6a4SAndroid Build Coastguard Worker fn push_descriptor(rd: RawDescriptor) -> Result<usize, &'static str> {
106*bb4ee6a4SAndroid Build Coastguard Worker     DESCRIPTOR_DST.with(|d| {
107*bb4ee6a4SAndroid Build Coastguard Worker         d.borrow_mut()
108*bb4ee6a4SAndroid Build Coastguard Worker             .as_mut()
109*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or("attempt to serialize descriptor without descriptor destination")
110*bb4ee6a4SAndroid Build Coastguard Worker             .map(|descriptors| {
111*bb4ee6a4SAndroid Build Coastguard Worker                 let index = descriptors.len();
112*bb4ee6a4SAndroid Build Coastguard Worker                 descriptors.push(rd);
113*bb4ee6a4SAndroid Build Coastguard Worker                 index
114*bb4ee6a4SAndroid Build Coastguard Worker             })
115*bb4ee6a4SAndroid Build Coastguard Worker     })
116*bb4ee6a4SAndroid Build Coastguard Worker }
117*bb4ee6a4SAndroid Build Coastguard Worker 
118*bb4ee6a4SAndroid Build Coastguard Worker /// Serializes a descriptor for later retrieval in a parent `SerializeDescriptors` struct.
119*bb4ee6a4SAndroid Build Coastguard Worker ///
120*bb4ee6a4SAndroid Build Coastguard Worker /// If there is no parent `SerializeDescriptors` being serialized, this will return an error.
121*bb4ee6a4SAndroid Build Coastguard Worker ///
122*bb4ee6a4SAndroid Build Coastguard Worker /// For convenience, it is recommended to use the `with_raw_descriptor` module in a `#[serde(with =
123*bb4ee6a4SAndroid Build Coastguard Worker /// "...")]` attribute which will make use of this function.
serialize_descriptor<S: Serializer>( rd: &RawDescriptor, se: S, ) -> std::result::Result<S::Ok, S::Error>124*bb4ee6a4SAndroid Build Coastguard Worker pub fn serialize_descriptor<S: Serializer>(
125*bb4ee6a4SAndroid Build Coastguard Worker     rd: &RawDescriptor,
126*bb4ee6a4SAndroid Build Coastguard Worker     se: S,
127*bb4ee6a4SAndroid Build Coastguard Worker ) -> std::result::Result<S::Ok, S::Error> {
128*bb4ee6a4SAndroid Build Coastguard Worker     let index = push_descriptor(*rd).map_err(ser::Error::custom)?;
129*bb4ee6a4SAndroid Build Coastguard Worker     se.serialize_u32(
130*bb4ee6a4SAndroid Build Coastguard Worker         index
131*bb4ee6a4SAndroid Build Coastguard Worker             .try_into()
132*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|_| ser::Error::custom("attempt to serialize too many descriptors at once"))?,
133*bb4ee6a4SAndroid Build Coastguard Worker     )
134*bb4ee6a4SAndroid Build Coastguard Worker }
135*bb4ee6a4SAndroid Build Coastguard Worker 
136*bb4ee6a4SAndroid Build Coastguard Worker /// Wrapper for a `Serialize` value which will capture any descriptors exported by the value when
137*bb4ee6a4SAndroid Build Coastguard Worker /// given to an ordinary `Serializer`.
138*bb4ee6a4SAndroid Build Coastguard Worker ///
139*bb4ee6a4SAndroid Build Coastguard Worker /// This is the corresponding type to use for serialization before using
140*bb4ee6a4SAndroid Build Coastguard Worker /// `deserialize_with_descriptors`.
141*bb4ee6a4SAndroid Build Coastguard Worker ///
142*bb4ee6a4SAndroid Build Coastguard Worker /// # Examples
143*bb4ee6a4SAndroid Build Coastguard Worker ///
144*bb4ee6a4SAndroid Build Coastguard Worker /// ```
145*bb4ee6a4SAndroid Build Coastguard Worker /// use serde_json::to_string;
146*bb4ee6a4SAndroid Build Coastguard Worker /// use base::{FileSerdeWrapper, SerializeDescriptors};
147*bb4ee6a4SAndroid Build Coastguard Worker /// use tempfile::tempfile;
148*bb4ee6a4SAndroid Build Coastguard Worker ///
149*bb4ee6a4SAndroid Build Coastguard Worker /// let tmp_f = tempfile().unwrap();
150*bb4ee6a4SAndroid Build Coastguard Worker /// let data = FileSerdeWrapper(tmp_f);
151*bb4ee6a4SAndroid Build Coastguard Worker /// let data_wrapper = SerializeDescriptors::new(&data);
152*bb4ee6a4SAndroid Build Coastguard Worker ///
153*bb4ee6a4SAndroid Build Coastguard Worker /// // Serializes `v` as normal...
154*bb4ee6a4SAndroid Build Coastguard Worker /// let out_json = serde_json::to_string(&data_wrapper).expect("failed to serialize");
155*bb4ee6a4SAndroid Build Coastguard Worker /// // If `serialize_descriptor` was called, we can capture the descriptors from here.
156*bb4ee6a4SAndroid Build Coastguard Worker /// let out_descriptors = data_wrapper.into_descriptors();
157*bb4ee6a4SAndroid Build Coastguard Worker /// ```
158*bb4ee6a4SAndroid Build Coastguard Worker pub struct SerializeDescriptors<'a, T: Serialize>(&'a T, Cell<Vec<RawDescriptor>>);
159*bb4ee6a4SAndroid Build Coastguard Worker 
160*bb4ee6a4SAndroid Build Coastguard Worker impl<'a, T: Serialize> SerializeDescriptors<'a, T> {
new(inner: &'a T) -> Self161*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(inner: &'a T) -> Self {
162*bb4ee6a4SAndroid Build Coastguard Worker         Self(inner, Default::default())
163*bb4ee6a4SAndroid Build Coastguard Worker     }
164*bb4ee6a4SAndroid Build Coastguard Worker 
into_descriptors(self) -> Vec<RawDescriptor>165*bb4ee6a4SAndroid Build Coastguard Worker     pub fn into_descriptors(self) -> Vec<RawDescriptor> {
166*bb4ee6a4SAndroid Build Coastguard Worker         self.1.into_inner()
167*bb4ee6a4SAndroid Build Coastguard Worker     }
168*bb4ee6a4SAndroid Build Coastguard Worker }
169*bb4ee6a4SAndroid Build Coastguard Worker 
170*bb4ee6a4SAndroid Build Coastguard Worker impl<'a, T: Serialize> Serialize for SerializeDescriptors<'a, T> {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,171*bb4ee6a4SAndroid Build Coastguard Worker     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
172*bb4ee6a4SAndroid Build Coastguard Worker     where
173*bb4ee6a4SAndroid Build Coastguard Worker         S: Serializer,
174*bb4ee6a4SAndroid Build Coastguard Worker     {
175*bb4ee6a4SAndroid Build Coastguard Worker         init_descriptor_dst().map_err(ser::Error::custom)?;
176*bb4ee6a4SAndroid Build Coastguard Worker 
177*bb4ee6a4SAndroid Build Coastguard Worker         // catch_unwind is used to ensure that init_descriptor_dst is always balanced with a call to
178*bb4ee6a4SAndroid Build Coastguard Worker         // take_descriptor_dst afterwards.
179*bb4ee6a4SAndroid Build Coastguard Worker         let res = catch_unwind(AssertUnwindSafe(|| self.0.serialize(serializer)));
180*bb4ee6a4SAndroid Build Coastguard Worker         self.1.set(take_descriptor_dst().unwrap());
181*bb4ee6a4SAndroid Build Coastguard Worker         match res {
182*bb4ee6a4SAndroid Build Coastguard Worker             Ok(r) => r,
183*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => resume_unwind(e),
184*bb4ee6a4SAndroid Build Coastguard Worker         }
185*bb4ee6a4SAndroid Build Coastguard Worker     }
186*bb4ee6a4SAndroid Build Coastguard Worker }
187*bb4ee6a4SAndroid Build Coastguard Worker 
188*bb4ee6a4SAndroid Build Coastguard Worker thread_local! {
189*bb4ee6a4SAndroid Build Coastguard Worker     static DESCRIPTOR_SRC: RefCell<Option<Vec<Option<SafeDescriptor>>>> = Default::default();
190*bb4ee6a4SAndroid Build Coastguard Worker }
191*bb4ee6a4SAndroid Build Coastguard Worker 
192*bb4ee6a4SAndroid Build Coastguard Worker /// Sets the thread local storage of descriptors for deserialization. Fails if this was already
193*bb4ee6a4SAndroid Build Coastguard Worker /// called without a call to `take_descriptor_src` on this thread.
194*bb4ee6a4SAndroid Build Coastguard Worker ///
195*bb4ee6a4SAndroid Build Coastguard Worker /// This is given as a collection of `Option` so that unused descriptors can be returned.
set_descriptor_src(descriptors: Vec<Option<SafeDescriptor>>) -> Result<(), &'static str>196*bb4ee6a4SAndroid Build Coastguard Worker fn set_descriptor_src(descriptors: Vec<Option<SafeDescriptor>>) -> Result<(), &'static str> {
197*bb4ee6a4SAndroid Build Coastguard Worker     DESCRIPTOR_SRC.with(|d| {
198*bb4ee6a4SAndroid Build Coastguard Worker         let mut src = d.borrow_mut();
199*bb4ee6a4SAndroid Build Coastguard Worker         if src.is_some() {
200*bb4ee6a4SAndroid Build Coastguard Worker             return Err("attempt to set descriptor source that was already set");
201*bb4ee6a4SAndroid Build Coastguard Worker         }
202*bb4ee6a4SAndroid Build Coastguard Worker         *src = Some(descriptors);
203*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
204*bb4ee6a4SAndroid Build Coastguard Worker     })
205*bb4ee6a4SAndroid Build Coastguard Worker }
206*bb4ee6a4SAndroid Build Coastguard Worker 
207*bb4ee6a4SAndroid Build Coastguard Worker /// Takes the thread local storage of descriptors for deserialization. Fails if the storage was
208*bb4ee6a4SAndroid Build Coastguard Worker /// already taken or never set with `set_descriptor_src`.
209*bb4ee6a4SAndroid Build Coastguard Worker ///
210*bb4ee6a4SAndroid Build Coastguard Worker /// If deserialization was done, the descriptors will mostly come back as `None` unless some of them
211*bb4ee6a4SAndroid Build Coastguard Worker /// were unused.
take_descriptor_src() -> Result<Vec<Option<SafeDescriptor>>, &'static str>212*bb4ee6a4SAndroid Build Coastguard Worker fn take_descriptor_src() -> Result<Vec<Option<SafeDescriptor>>, &'static str> {
213*bb4ee6a4SAndroid Build Coastguard Worker     DESCRIPTOR_SRC.with(|d| {
214*bb4ee6a4SAndroid Build Coastguard Worker         d.replace(None)
215*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or("attempt to take descriptor source which was never set")
216*bb4ee6a4SAndroid Build Coastguard Worker     })
217*bb4ee6a4SAndroid Build Coastguard Worker }
218*bb4ee6a4SAndroid Build Coastguard Worker 
219*bb4ee6a4SAndroid Build Coastguard Worker /// Takes a descriptor at the given index from the thread local source of descriptors.
220*bb4ee6a4SAndroid Build Coastguard Worker //
221*bb4ee6a4SAndroid Build Coastguard Worker /// Returns None if the thread local source was not already initialized.
take_descriptor(index: usize) -> Result<SafeDescriptor, &'static str>222*bb4ee6a4SAndroid Build Coastguard Worker fn take_descriptor(index: usize) -> Result<SafeDescriptor, &'static str> {
223*bb4ee6a4SAndroid Build Coastguard Worker     DESCRIPTOR_SRC.with(|d| {
224*bb4ee6a4SAndroid Build Coastguard Worker         d.borrow_mut()
225*bb4ee6a4SAndroid Build Coastguard Worker             .as_mut()
226*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or("attempt to deserialize descriptor without descriptor source")?
227*bb4ee6a4SAndroid Build Coastguard Worker             .get_mut(index)
228*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or("attempt to deserialize out of bounds descriptor")?
229*bb4ee6a4SAndroid Build Coastguard Worker             .take()
230*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or("attempt to deserialize descriptor that was already taken")
231*bb4ee6a4SAndroid Build Coastguard Worker     })
232*bb4ee6a4SAndroid Build Coastguard Worker }
233*bb4ee6a4SAndroid Build Coastguard Worker 
234*bb4ee6a4SAndroid Build Coastguard Worker /// Deserializes a descriptor provided via `deserialize_with_descriptors`.
235*bb4ee6a4SAndroid Build Coastguard Worker ///
236*bb4ee6a4SAndroid Build Coastguard Worker /// If `deserialize_with_descriptors` is not in the call chain, this will return an error.
237*bb4ee6a4SAndroid Build Coastguard Worker ///
238*bb4ee6a4SAndroid Build Coastguard Worker /// For convenience, it is recommended to use the `with_raw_descriptor` module in a `#[serde(with =
239*bb4ee6a4SAndroid Build Coastguard Worker /// "...")]` attribute which will make use of this function.
deserialize_descriptor<'de, D>(de: D) -> std::result::Result<SafeDescriptor, D::Error> where D: Deserializer<'de>,240*bb4ee6a4SAndroid Build Coastguard Worker pub fn deserialize_descriptor<'de, D>(de: D) -> std::result::Result<SafeDescriptor, D::Error>
241*bb4ee6a4SAndroid Build Coastguard Worker where
242*bb4ee6a4SAndroid Build Coastguard Worker     D: Deserializer<'de>,
243*bb4ee6a4SAndroid Build Coastguard Worker {
244*bb4ee6a4SAndroid Build Coastguard Worker     struct DescriptorVisitor;
245*bb4ee6a4SAndroid Build Coastguard Worker 
246*bb4ee6a4SAndroid Build Coastguard Worker     impl<'de> Visitor<'de> for DescriptorVisitor {
247*bb4ee6a4SAndroid Build Coastguard Worker         type Value = u32;
248*bb4ee6a4SAndroid Build Coastguard Worker 
249*bb4ee6a4SAndroid Build Coastguard Worker         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
250*bb4ee6a4SAndroid Build Coastguard Worker             formatter.write_str("an integer which fits into a u32")
251*bb4ee6a4SAndroid Build Coastguard Worker         }
252*bb4ee6a4SAndroid Build Coastguard Worker 
253*bb4ee6a4SAndroid Build Coastguard Worker         fn visit_u8<E: de::Error>(self, value: u8) -> Result<Self::Value, E> {
254*bb4ee6a4SAndroid Build Coastguard Worker             Ok(value as _)
255*bb4ee6a4SAndroid Build Coastguard Worker         }
256*bb4ee6a4SAndroid Build Coastguard Worker 
257*bb4ee6a4SAndroid Build Coastguard Worker         fn visit_u16<E: de::Error>(self, value: u16) -> Result<Self::Value, E> {
258*bb4ee6a4SAndroid Build Coastguard Worker             Ok(value as _)
259*bb4ee6a4SAndroid Build Coastguard Worker         }
260*bb4ee6a4SAndroid Build Coastguard Worker 
261*bb4ee6a4SAndroid Build Coastguard Worker         fn visit_u32<E: de::Error>(self, value: u32) -> Result<Self::Value, E> {
262*bb4ee6a4SAndroid Build Coastguard Worker             Ok(value)
263*bb4ee6a4SAndroid Build Coastguard Worker         }
264*bb4ee6a4SAndroid Build Coastguard Worker 
265*bb4ee6a4SAndroid Build Coastguard Worker         fn visit_u64<E: de::Error>(self, value: u64) -> Result<Self::Value, E> {
266*bb4ee6a4SAndroid Build Coastguard Worker             value.try_into().map_err(E::custom)
267*bb4ee6a4SAndroid Build Coastguard Worker         }
268*bb4ee6a4SAndroid Build Coastguard Worker 
269*bb4ee6a4SAndroid Build Coastguard Worker         fn visit_u128<E: de::Error>(self, value: u128) -> Result<Self::Value, E> {
270*bb4ee6a4SAndroid Build Coastguard Worker             value.try_into().map_err(E::custom)
271*bb4ee6a4SAndroid Build Coastguard Worker         }
272*bb4ee6a4SAndroid Build Coastguard Worker 
273*bb4ee6a4SAndroid Build Coastguard Worker         fn visit_i8<E: de::Error>(self, value: i8) -> Result<Self::Value, E> {
274*bb4ee6a4SAndroid Build Coastguard Worker             value.try_into().map_err(E::custom)
275*bb4ee6a4SAndroid Build Coastguard Worker         }
276*bb4ee6a4SAndroid Build Coastguard Worker 
277*bb4ee6a4SAndroid Build Coastguard Worker         fn visit_i16<E: de::Error>(self, value: i16) -> Result<Self::Value, E> {
278*bb4ee6a4SAndroid Build Coastguard Worker             value.try_into().map_err(E::custom)
279*bb4ee6a4SAndroid Build Coastguard Worker         }
280*bb4ee6a4SAndroid Build Coastguard Worker 
281*bb4ee6a4SAndroid Build Coastguard Worker         fn visit_i32<E: de::Error>(self, value: i32) -> Result<Self::Value, E> {
282*bb4ee6a4SAndroid Build Coastguard Worker             value.try_into().map_err(E::custom)
283*bb4ee6a4SAndroid Build Coastguard Worker         }
284*bb4ee6a4SAndroid Build Coastguard Worker 
285*bb4ee6a4SAndroid Build Coastguard Worker         fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> {
286*bb4ee6a4SAndroid Build Coastguard Worker             value.try_into().map_err(E::custom)
287*bb4ee6a4SAndroid Build Coastguard Worker         }
288*bb4ee6a4SAndroid Build Coastguard Worker 
289*bb4ee6a4SAndroid Build Coastguard Worker         fn visit_i128<E: de::Error>(self, value: i128) -> Result<Self::Value, E> {
290*bb4ee6a4SAndroid Build Coastguard Worker             value.try_into().map_err(E::custom)
291*bb4ee6a4SAndroid Build Coastguard Worker         }
292*bb4ee6a4SAndroid Build Coastguard Worker     }
293*bb4ee6a4SAndroid Build Coastguard Worker 
294*bb4ee6a4SAndroid Build Coastguard Worker     let index = de.deserialize_u32(DescriptorVisitor)? as usize;
295*bb4ee6a4SAndroid Build Coastguard Worker     take_descriptor(index).map_err(D::Error::custom)
296*bb4ee6a4SAndroid Build Coastguard Worker }
297*bb4ee6a4SAndroid Build Coastguard Worker 
298*bb4ee6a4SAndroid Build Coastguard Worker /// Allows the use of any serde deserializer within a closure while providing access to the a set of
299*bb4ee6a4SAndroid Build Coastguard Worker /// descriptors for use in `deserialize_descriptor`.
300*bb4ee6a4SAndroid Build Coastguard Worker ///
301*bb4ee6a4SAndroid Build Coastguard Worker /// This is the corresponding call to use deserialize after using `SerializeDescriptors`.
302*bb4ee6a4SAndroid Build Coastguard Worker ///
303*bb4ee6a4SAndroid Build Coastguard Worker /// If `deserialize_with_descriptors` is called anywhere within the given closure, it return an
304*bb4ee6a4SAndroid Build Coastguard Worker /// error.
deserialize_with_descriptors<F, T, E>( f: F, descriptors: impl IntoIterator<Item = SafeDescriptor>, ) -> Result<T, E> where F: FnOnce() -> Result<T, E>, E: de::Error,305*bb4ee6a4SAndroid Build Coastguard Worker pub fn deserialize_with_descriptors<F, T, E>(
306*bb4ee6a4SAndroid Build Coastguard Worker     f: F,
307*bb4ee6a4SAndroid Build Coastguard Worker     descriptors: impl IntoIterator<Item = SafeDescriptor>,
308*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<T, E>
309*bb4ee6a4SAndroid Build Coastguard Worker where
310*bb4ee6a4SAndroid Build Coastguard Worker     F: FnOnce() -> Result<T, E>,
311*bb4ee6a4SAndroid Build Coastguard Worker     E: de::Error,
312*bb4ee6a4SAndroid Build Coastguard Worker {
313*bb4ee6a4SAndroid Build Coastguard Worker     let descriptor_src = descriptors.into_iter().map(Option::Some).collect();
314*bb4ee6a4SAndroid Build Coastguard Worker     set_descriptor_src(descriptor_src).map_err(E::custom)?;
315*bb4ee6a4SAndroid Build Coastguard Worker 
316*bb4ee6a4SAndroid Build Coastguard Worker     // catch_unwind is used to ensure that set_descriptor_src is always balanced with a call to
317*bb4ee6a4SAndroid Build Coastguard Worker     // take_descriptor_src afterwards.
318*bb4ee6a4SAndroid Build Coastguard Worker     let res = catch_unwind(AssertUnwindSafe(f));
319*bb4ee6a4SAndroid Build Coastguard Worker 
320*bb4ee6a4SAndroid Build Coastguard Worker     // unwrap is used because set_descriptor_src is always called before this, so it should never
321*bb4ee6a4SAndroid Build Coastguard Worker     // panic.
322*bb4ee6a4SAndroid Build Coastguard Worker     let empty_descriptors = take_descriptor_src().unwrap();
323*bb4ee6a4SAndroid Build Coastguard Worker 
324*bb4ee6a4SAndroid Build Coastguard Worker     // The deserializer should have consumed every descriptor.
325*bb4ee6a4SAndroid Build Coastguard Worker     debug_assert!(empty_descriptors.into_iter().all(|d| d.is_none()));
326*bb4ee6a4SAndroid Build Coastguard Worker 
327*bb4ee6a4SAndroid Build Coastguard Worker     match res {
328*bb4ee6a4SAndroid Build Coastguard Worker         Ok(r) => r,
329*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => resume_unwind(e),
330*bb4ee6a4SAndroid Build Coastguard Worker     }
331*bb4ee6a4SAndroid Build Coastguard Worker }
332*bb4ee6a4SAndroid Build Coastguard Worker 
333*bb4ee6a4SAndroid Build Coastguard Worker /// Module that exports `serialize`/`deserialize` functions for use with `#[serde(with = "...")]`
334*bb4ee6a4SAndroid Build Coastguard Worker /// attribute. It only works with fields with `RawDescriptor` type.
335*bb4ee6a4SAndroid Build Coastguard Worker ///
336*bb4ee6a4SAndroid Build Coastguard Worker /// # Examples
337*bb4ee6a4SAndroid Build Coastguard Worker ///
338*bb4ee6a4SAndroid Build Coastguard Worker /// ```
339*bb4ee6a4SAndroid Build Coastguard Worker /// use serde::{Deserialize, Serialize};
340*bb4ee6a4SAndroid Build Coastguard Worker /// use base::RawDescriptor;
341*bb4ee6a4SAndroid Build Coastguard Worker ///
342*bb4ee6a4SAndroid Build Coastguard Worker /// #[derive(Serialize, Deserialize)]
343*bb4ee6a4SAndroid Build Coastguard Worker /// struct RawContainer {
344*bb4ee6a4SAndroid Build Coastguard Worker ///     #[serde(with = "base::with_raw_descriptor")]
345*bb4ee6a4SAndroid Build Coastguard Worker ///     rd: RawDescriptor,
346*bb4ee6a4SAndroid Build Coastguard Worker /// }
347*bb4ee6a4SAndroid Build Coastguard Worker /// ```
348*bb4ee6a4SAndroid Build Coastguard Worker pub mod with_raw_descriptor {
349*bb4ee6a4SAndroid Build Coastguard Worker     use serde::Deserializer;
350*bb4ee6a4SAndroid Build Coastguard Worker 
351*bb4ee6a4SAndroid Build Coastguard Worker     use super::super::RawDescriptor;
352*bb4ee6a4SAndroid Build Coastguard Worker     pub use super::serialize_descriptor as serialize;
353*bb4ee6a4SAndroid Build Coastguard Worker     use crate::descriptor::IntoRawDescriptor;
354*bb4ee6a4SAndroid Build Coastguard Worker 
deserialize<'de, D>(de: D) -> std::result::Result<RawDescriptor, D::Error> where D: Deserializer<'de>,355*bb4ee6a4SAndroid Build Coastguard Worker     pub fn deserialize<'de, D>(de: D) -> std::result::Result<RawDescriptor, D::Error>
356*bb4ee6a4SAndroid Build Coastguard Worker     where
357*bb4ee6a4SAndroid Build Coastguard Worker         D: Deserializer<'de>,
358*bb4ee6a4SAndroid Build Coastguard Worker     {
359*bb4ee6a4SAndroid Build Coastguard Worker         super::deserialize_descriptor(de).map(IntoRawDescriptor::into_raw_descriptor)
360*bb4ee6a4SAndroid Build Coastguard Worker     }
361*bb4ee6a4SAndroid Build Coastguard Worker }
362*bb4ee6a4SAndroid Build Coastguard Worker 
363*bb4ee6a4SAndroid Build Coastguard Worker /// Module that exports `serialize`/`deserialize` functions for use with `#[serde(with = "...")]`
364*bb4ee6a4SAndroid Build Coastguard Worker /// attribute.
365*bb4ee6a4SAndroid Build Coastguard Worker ///
366*bb4ee6a4SAndroid Build Coastguard Worker /// # Examples
367*bb4ee6a4SAndroid Build Coastguard Worker ///
368*bb4ee6a4SAndroid Build Coastguard Worker /// ```
369*bb4ee6a4SAndroid Build Coastguard Worker /// use std::fs::File;
370*bb4ee6a4SAndroid Build Coastguard Worker /// use serde::{Deserialize, Serialize};
371*bb4ee6a4SAndroid Build Coastguard Worker /// use base::RawDescriptor;
372*bb4ee6a4SAndroid Build Coastguard Worker ///
373*bb4ee6a4SAndroid Build Coastguard Worker /// #[derive(Serialize, Deserialize)]
374*bb4ee6a4SAndroid Build Coastguard Worker /// struct FileContainer {
375*bb4ee6a4SAndroid Build Coastguard Worker ///     #[serde(with = "base::with_as_descriptor")]
376*bb4ee6a4SAndroid Build Coastguard Worker ///     file: File,
377*bb4ee6a4SAndroid Build Coastguard Worker /// }
378*bb4ee6a4SAndroid Build Coastguard Worker /// ```
379*bb4ee6a4SAndroid Build Coastguard Worker pub mod with_as_descriptor {
380*bb4ee6a4SAndroid Build Coastguard Worker     use serde::Deserializer;
381*bb4ee6a4SAndroid Build Coastguard Worker     use serde::Serializer;
382*bb4ee6a4SAndroid Build Coastguard Worker 
383*bb4ee6a4SAndroid Build Coastguard Worker     use crate::descriptor::AsRawDescriptor;
384*bb4ee6a4SAndroid Build Coastguard Worker     use crate::descriptor::FromRawDescriptor;
385*bb4ee6a4SAndroid Build Coastguard Worker     use crate::descriptor::IntoRawDescriptor;
386*bb4ee6a4SAndroid Build Coastguard Worker 
serialize<S: Serializer>( rd: &dyn AsRawDescriptor, se: S, ) -> std::result::Result<S::Ok, S::Error>387*bb4ee6a4SAndroid Build Coastguard Worker     pub fn serialize<S: Serializer>(
388*bb4ee6a4SAndroid Build Coastguard Worker         rd: &dyn AsRawDescriptor,
389*bb4ee6a4SAndroid Build Coastguard Worker         se: S,
390*bb4ee6a4SAndroid Build Coastguard Worker     ) -> std::result::Result<S::Ok, S::Error> {
391*bb4ee6a4SAndroid Build Coastguard Worker         super::serialize_descriptor(&rd.as_raw_descriptor(), se)
392*bb4ee6a4SAndroid Build Coastguard Worker     }
393*bb4ee6a4SAndroid Build Coastguard Worker 
deserialize<'de, D, T>(de: D) -> std::result::Result<T, D::Error> where D: Deserializer<'de>, T: FromRawDescriptor,394*bb4ee6a4SAndroid Build Coastguard Worker     pub fn deserialize<'de, D, T>(de: D) -> std::result::Result<T, D::Error>
395*bb4ee6a4SAndroid Build Coastguard Worker     where
396*bb4ee6a4SAndroid Build Coastguard Worker         D: Deserializer<'de>,
397*bb4ee6a4SAndroid Build Coastguard Worker         T: FromRawDescriptor,
398*bb4ee6a4SAndroid Build Coastguard Worker     {
399*bb4ee6a4SAndroid Build Coastguard Worker         super::deserialize_descriptor(de)
400*bb4ee6a4SAndroid Build Coastguard Worker             .map(IntoRawDescriptor::into_raw_descriptor)
401*bb4ee6a4SAndroid Build Coastguard Worker             .map(|rd|
402*bb4ee6a4SAndroid Build Coastguard Worker                 // SAFETY: rd is expected to be valid for the duration of the call.
403*bb4ee6a4SAndroid Build Coastguard Worker                 unsafe { T::from_raw_descriptor(rd) })
404*bb4ee6a4SAndroid Build Coastguard Worker     }
405*bb4ee6a4SAndroid Build Coastguard Worker }
406*bb4ee6a4SAndroid Build Coastguard Worker 
407*bb4ee6a4SAndroid Build Coastguard Worker /// A simple wrapper around `File` that implements `Serialize`/`Deserialize`, which is useful when
408*bb4ee6a4SAndroid Build Coastguard Worker /// the `#[serde(with = "with_as_descriptor")]` trait is infeasible, such as for a field with type
409*bb4ee6a4SAndroid Build Coastguard Worker /// `Option<File>`.
410*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)]
411*bb4ee6a4SAndroid Build Coastguard Worker #[serde(transparent)]
412*bb4ee6a4SAndroid Build Coastguard Worker pub struct FileSerdeWrapper(#[serde(with = "with_as_descriptor")] pub File);
413*bb4ee6a4SAndroid Build Coastguard Worker 
414*bb4ee6a4SAndroid Build Coastguard Worker impl fmt::Debug for FileSerdeWrapper {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result415*bb4ee6a4SAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
416*bb4ee6a4SAndroid Build Coastguard Worker         self.0.fmt(f)
417*bb4ee6a4SAndroid Build Coastguard Worker     }
418*bb4ee6a4SAndroid Build Coastguard Worker }
419*bb4ee6a4SAndroid Build Coastguard Worker 
420*bb4ee6a4SAndroid Build Coastguard Worker impl From<File> for FileSerdeWrapper {
from(file: File) -> Self421*bb4ee6a4SAndroid Build Coastguard Worker     fn from(file: File) -> Self {
422*bb4ee6a4SAndroid Build Coastguard Worker         FileSerdeWrapper(file)
423*bb4ee6a4SAndroid Build Coastguard Worker     }
424*bb4ee6a4SAndroid Build Coastguard Worker }
425*bb4ee6a4SAndroid Build Coastguard Worker 
426*bb4ee6a4SAndroid Build Coastguard Worker impl From<FileSerdeWrapper> for File {
from(f: FileSerdeWrapper) -> File427*bb4ee6a4SAndroid Build Coastguard Worker     fn from(f: FileSerdeWrapper) -> File {
428*bb4ee6a4SAndroid Build Coastguard Worker         f.0
429*bb4ee6a4SAndroid Build Coastguard Worker     }
430*bb4ee6a4SAndroid Build Coastguard Worker }
431*bb4ee6a4SAndroid Build Coastguard Worker 
432*bb4ee6a4SAndroid Build Coastguard Worker impl Deref for FileSerdeWrapper {
433*bb4ee6a4SAndroid Build Coastguard Worker     type Target = File;
deref(&self) -> &Self::Target434*bb4ee6a4SAndroid Build Coastguard Worker     fn deref(&self) -> &Self::Target {
435*bb4ee6a4SAndroid Build Coastguard Worker         &self.0
436*bb4ee6a4SAndroid Build Coastguard Worker     }
437*bb4ee6a4SAndroid Build Coastguard Worker }
438*bb4ee6a4SAndroid Build Coastguard Worker 
439*bb4ee6a4SAndroid Build Coastguard Worker impl DerefMut for FileSerdeWrapper {
deref_mut(&mut self) -> &mut Self::Target440*bb4ee6a4SAndroid Build Coastguard Worker     fn deref_mut(&mut self) -> &mut Self::Target {
441*bb4ee6a4SAndroid Build Coastguard Worker         &mut self.0
442*bb4ee6a4SAndroid Build Coastguard Worker     }
443*bb4ee6a4SAndroid Build Coastguard Worker }
444*bb4ee6a4SAndroid Build Coastguard Worker 
445*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
446*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
447*bb4ee6a4SAndroid Build Coastguard Worker     use std::collections::HashMap;
448*bb4ee6a4SAndroid Build Coastguard Worker     use std::fs::File;
449*bb4ee6a4SAndroid Build Coastguard Worker     use std::mem::ManuallyDrop;
450*bb4ee6a4SAndroid Build Coastguard Worker 
451*bb4ee6a4SAndroid Build Coastguard Worker     use serde::de::DeserializeOwned;
452*bb4ee6a4SAndroid Build Coastguard Worker     use serde::Deserialize;
453*bb4ee6a4SAndroid Build Coastguard Worker     use serde::Serialize;
454*bb4ee6a4SAndroid Build Coastguard Worker     use tempfile::tempfile;
455*bb4ee6a4SAndroid Build Coastguard Worker 
456*bb4ee6a4SAndroid Build Coastguard Worker     use super::super::deserialize_with_descriptors;
457*bb4ee6a4SAndroid Build Coastguard Worker     use super::super::with_as_descriptor;
458*bb4ee6a4SAndroid Build Coastguard Worker     use super::super::with_raw_descriptor;
459*bb4ee6a4SAndroid Build Coastguard Worker     use super::super::AsRawDescriptor;
460*bb4ee6a4SAndroid Build Coastguard Worker     use super::super::FileSerdeWrapper;
461*bb4ee6a4SAndroid Build Coastguard Worker     use super::super::FromRawDescriptor;
462*bb4ee6a4SAndroid Build Coastguard Worker     use super::super::RawDescriptor;
463*bb4ee6a4SAndroid Build Coastguard Worker     use super::super::SafeDescriptor;
464*bb4ee6a4SAndroid Build Coastguard Worker     use super::super::SerializeDescriptors;
465*bb4ee6a4SAndroid Build Coastguard Worker 
deserialize<T: DeserializeOwned>(json: &str, descriptors: &[RawDescriptor]) -> T466*bb4ee6a4SAndroid Build Coastguard Worker     fn deserialize<T: DeserializeOwned>(json: &str, descriptors: &[RawDescriptor]) -> T {
467*bb4ee6a4SAndroid Build Coastguard Worker         let safe_descriptors = descriptors.iter().map(|&v|
468*bb4ee6a4SAndroid Build Coastguard Worker                 // SAFETY: `descriptor` is expected to be valid.
469*bb4ee6a4SAndroid Build Coastguard Worker                 unsafe { SafeDescriptor::from_raw_descriptor(v) });
470*bb4ee6a4SAndroid Build Coastguard Worker 
471*bb4ee6a4SAndroid Build Coastguard Worker         deserialize_with_descriptors(|| serde_json::from_str(json), safe_descriptors).unwrap()
472*bb4ee6a4SAndroid Build Coastguard Worker     }
473*bb4ee6a4SAndroid Build Coastguard Worker 
474*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
raw()475*bb4ee6a4SAndroid Build Coastguard Worker     fn raw() {
476*bb4ee6a4SAndroid Build Coastguard Worker         #[derive(Serialize, Deserialize, PartialEq, Debug)]
477*bb4ee6a4SAndroid Build Coastguard Worker         struct RawContainer {
478*bb4ee6a4SAndroid Build Coastguard Worker             #[serde(with = "with_raw_descriptor")]
479*bb4ee6a4SAndroid Build Coastguard Worker             rd: RawDescriptor,
480*bb4ee6a4SAndroid Build Coastguard Worker         }
481*bb4ee6a4SAndroid Build Coastguard Worker         // Specifically chosen to not overlap a real descriptor to avoid having to allocate any
482*bb4ee6a4SAndroid Build Coastguard Worker         // descriptors for this test.
483*bb4ee6a4SAndroid Build Coastguard Worker         let fake_rd = 5_123_457_i32;
484*bb4ee6a4SAndroid Build Coastguard Worker         let v = RawContainer {
485*bb4ee6a4SAndroid Build Coastguard Worker             rd: fake_rd as RawDescriptor,
486*bb4ee6a4SAndroid Build Coastguard Worker         };
487*bb4ee6a4SAndroid Build Coastguard Worker         let v_serialize = SerializeDescriptors::new(&v);
488*bb4ee6a4SAndroid Build Coastguard Worker         let json = serde_json::to_string(&v_serialize).unwrap();
489*bb4ee6a4SAndroid Build Coastguard Worker         let descriptors = v_serialize.into_descriptors();
490*bb4ee6a4SAndroid Build Coastguard Worker         let res = deserialize(&json, &descriptors);
491*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(v, res);
492*bb4ee6a4SAndroid Build Coastguard Worker     }
493*bb4ee6a4SAndroid Build Coastguard Worker 
494*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
file()495*bb4ee6a4SAndroid Build Coastguard Worker     fn file() {
496*bb4ee6a4SAndroid Build Coastguard Worker         #[derive(Serialize, Deserialize)]
497*bb4ee6a4SAndroid Build Coastguard Worker         struct FileContainer {
498*bb4ee6a4SAndroid Build Coastguard Worker             #[serde(with = "with_as_descriptor")]
499*bb4ee6a4SAndroid Build Coastguard Worker             file: File,
500*bb4ee6a4SAndroid Build Coastguard Worker         }
501*bb4ee6a4SAndroid Build Coastguard Worker 
502*bb4ee6a4SAndroid Build Coastguard Worker         let v = FileContainer {
503*bb4ee6a4SAndroid Build Coastguard Worker             file: tempfile().unwrap(),
504*bb4ee6a4SAndroid Build Coastguard Worker         };
505*bb4ee6a4SAndroid Build Coastguard Worker         let v_serialize = SerializeDescriptors::new(&v);
506*bb4ee6a4SAndroid Build Coastguard Worker         let json = serde_json::to_string(&v_serialize).unwrap();
507*bb4ee6a4SAndroid Build Coastguard Worker         let descriptors = v_serialize.into_descriptors();
508*bb4ee6a4SAndroid Build Coastguard Worker         let v = ManuallyDrop::new(v);
509*bb4ee6a4SAndroid Build Coastguard Worker         let res: FileContainer = deserialize(&json, &descriptors);
510*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(v.file.as_raw_descriptor(), res.file.as_raw_descriptor());
511*bb4ee6a4SAndroid Build Coastguard Worker     }
512*bb4ee6a4SAndroid Build Coastguard Worker 
513*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
option()514*bb4ee6a4SAndroid Build Coastguard Worker     fn option() {
515*bb4ee6a4SAndroid Build Coastguard Worker         #[derive(Serialize, Deserialize)]
516*bb4ee6a4SAndroid Build Coastguard Worker         struct TestOption {
517*bb4ee6a4SAndroid Build Coastguard Worker             a: Option<FileSerdeWrapper>,
518*bb4ee6a4SAndroid Build Coastguard Worker             b: Option<FileSerdeWrapper>,
519*bb4ee6a4SAndroid Build Coastguard Worker         }
520*bb4ee6a4SAndroid Build Coastguard Worker 
521*bb4ee6a4SAndroid Build Coastguard Worker         let v = TestOption {
522*bb4ee6a4SAndroid Build Coastguard Worker             a: None,
523*bb4ee6a4SAndroid Build Coastguard Worker             b: Some(tempfile().unwrap().into()),
524*bb4ee6a4SAndroid Build Coastguard Worker         };
525*bb4ee6a4SAndroid Build Coastguard Worker         let v_serialize = SerializeDescriptors::new(&v);
526*bb4ee6a4SAndroid Build Coastguard Worker         let json = serde_json::to_string(&v_serialize).unwrap();
527*bb4ee6a4SAndroid Build Coastguard Worker         let descriptors = v_serialize.into_descriptors();
528*bb4ee6a4SAndroid Build Coastguard Worker         let v = ManuallyDrop::new(v);
529*bb4ee6a4SAndroid Build Coastguard Worker         let res: TestOption = deserialize(&json, &descriptors);
530*bb4ee6a4SAndroid Build Coastguard Worker         assert!(res.a.is_none());
531*bb4ee6a4SAndroid Build Coastguard Worker         assert!(res.b.is_some());
532*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
533*bb4ee6a4SAndroid Build Coastguard Worker             v.b.as_ref().unwrap().as_raw_descriptor(),
534*bb4ee6a4SAndroid Build Coastguard Worker             res.b.unwrap().as_raw_descriptor()
535*bb4ee6a4SAndroid Build Coastguard Worker         );
536*bb4ee6a4SAndroid Build Coastguard Worker     }
537*bb4ee6a4SAndroid Build Coastguard Worker 
538*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
map()539*bb4ee6a4SAndroid Build Coastguard Worker     fn map() {
540*bb4ee6a4SAndroid Build Coastguard Worker         let mut v: HashMap<String, FileSerdeWrapper> = HashMap::new();
541*bb4ee6a4SAndroid Build Coastguard Worker         v.insert("a".into(), tempfile().unwrap().into());
542*bb4ee6a4SAndroid Build Coastguard Worker         v.insert("b".into(), tempfile().unwrap().into());
543*bb4ee6a4SAndroid Build Coastguard Worker         v.insert("c".into(), tempfile().unwrap().into());
544*bb4ee6a4SAndroid Build Coastguard Worker         let v_serialize = SerializeDescriptors::new(&v);
545*bb4ee6a4SAndroid Build Coastguard Worker         let json = serde_json::to_string(&v_serialize).unwrap();
546*bb4ee6a4SAndroid Build Coastguard Worker         let descriptors = v_serialize.into_descriptors();
547*bb4ee6a4SAndroid Build Coastguard Worker         // Prevent the files in `v` from dropping while allowing the HashMap itself to drop. It is
548*bb4ee6a4SAndroid Build Coastguard Worker         // done this way to prevent a double close of the files (which should reside in `res`)
549*bb4ee6a4SAndroid Build Coastguard Worker         // without triggering the leak sanitizer on `v`'s HashMap heap memory.
550*bb4ee6a4SAndroid Build Coastguard Worker         let v: HashMap<_, _> = v
551*bb4ee6a4SAndroid Build Coastguard Worker             .into_iter()
552*bb4ee6a4SAndroid Build Coastguard Worker             .map(|(k, v)| (k, ManuallyDrop::new(v)))
553*bb4ee6a4SAndroid Build Coastguard Worker             .collect();
554*bb4ee6a4SAndroid Build Coastguard Worker         let res: HashMap<String, FileSerdeWrapper> = deserialize(&json, &descriptors);
555*bb4ee6a4SAndroid Build Coastguard Worker 
556*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(v.len(), res.len());
557*bb4ee6a4SAndroid Build Coastguard Worker         for (k, v) in v.iter() {
558*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(
559*bb4ee6a4SAndroid Build Coastguard Worker                 res.get(k).unwrap().as_raw_descriptor(),
560*bb4ee6a4SAndroid Build Coastguard Worker                 v.as_raw_descriptor()
561*bb4ee6a4SAndroid Build Coastguard Worker             );
562*bb4ee6a4SAndroid Build Coastguard Worker         }
563*bb4ee6a4SAndroid Build Coastguard Worker     }
564*bb4ee6a4SAndroid Build Coastguard Worker }
565