• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //! This module contains types required to export ICU4X data via the `icu_provider_export` crate.
6 //! End users should not need to consume anything in this module.
7 //!
8 //! This module is enabled with the `export` Cargo feature.
9 
10 mod payload;
11 
12 pub use payload::{ExportBox, ExportMarker};
13 
14 use crate::prelude::*;
15 use alloc::collections::BTreeSet;
16 
17 /// An object capable of exporting data payloads in some form.
18 pub trait DataExporter: Sync {
19     /// Save a `payload` corresponding to the given marker and locale.
20     ///
21     /// Takes non-mut self as it can be called concurrently.
put_payload( &self, marker: DataMarkerInfo, id: DataIdentifierBorrowed, payload: &DataPayload<ExportMarker>, ) -> Result<(), DataError>22     fn put_payload(
23         &self,
24         marker: DataMarkerInfo,
25         id: DataIdentifierBorrowed,
26         payload: &DataPayload<ExportMarker>,
27     ) -> Result<(), DataError>;
28 
29     /// Function called for singleton markers.
30     ///
31     /// Takes non-mut self as it can be called concurrently.
flush_singleton( &self, marker: DataMarkerInfo, payload: &DataPayload<ExportMarker>, metadata: FlushMetadata, ) -> Result<(), DataError>32     fn flush_singleton(
33         &self,
34         marker: DataMarkerInfo,
35         payload: &DataPayload<ExportMarker>,
36         metadata: FlushMetadata,
37     ) -> Result<(), DataError> {
38         self.put_payload(marker, Default::default(), payload)?;
39         self.flush(marker, metadata)
40     }
41 
42     /// Function called after a non-singleton marker has been fully enumerated.
43     ///
44     /// Takes non-mut self as it can be called concurrently.
flush(&self, _marker: DataMarkerInfo, _metadata: FlushMetadata) -> Result<(), DataError>45     fn flush(&self, _marker: DataMarkerInfo, _metadata: FlushMetadata) -> Result<(), DataError> {
46         Ok(())
47     }
48 
49     /// This function has to be called before the object is dropped (after all
50     /// markers have been fully dumped). This conceptually takes ownership, so
51     /// clients *may not* interact with this object after close has been called.
close(&mut self) -> Result<ExporterCloseMetadata, DataError>52     fn close(&mut self) -> Result<ExporterCloseMetadata, DataError> {
53         Ok(ExporterCloseMetadata::default())
54     }
55 }
56 
57 #[derive(Debug, Default)]
58 #[allow(clippy::exhaustive_structs)] // newtype
59 /// Contains information about a successful export.
60 pub struct ExporterCloseMetadata(pub Option<Box<dyn core::any::Any>>);
61 
62 /// Metadata for [`DataExporter::flush`]
63 #[non_exhaustive]
64 #[derive(Debug, Copy, Clone, Default)]
65 pub struct FlushMetadata {
66     /// Whether the data was generated in such a way that a [`DryDataProvider`] implementation
67     /// makes sense.
68     pub supports_dry_provider: bool,
69     /// The checksum to return with this data marker.
70     pub checksum: Option<u64>,
71 }
72 
73 impl DataExporter for Box<dyn DataExporter> {
put_payload( &self, marker: DataMarkerInfo, id: DataIdentifierBorrowed, payload: &DataPayload<ExportMarker>, ) -> Result<(), DataError>74     fn put_payload(
75         &self,
76         marker: DataMarkerInfo,
77         id: DataIdentifierBorrowed,
78         payload: &DataPayload<ExportMarker>,
79     ) -> Result<(), DataError> {
80         (**self).put_payload(marker, id, payload)
81     }
82 
flush_singleton( &self, marker: DataMarkerInfo, payload: &DataPayload<ExportMarker>, metadata: FlushMetadata, ) -> Result<(), DataError>83     fn flush_singleton(
84         &self,
85         marker: DataMarkerInfo,
86         payload: &DataPayload<ExportMarker>,
87         metadata: FlushMetadata,
88     ) -> Result<(), DataError> {
89         (**self).flush_singleton(marker, payload, metadata)
90     }
91 
flush(&self, marker: DataMarkerInfo, metadata: FlushMetadata) -> Result<(), DataError>92     fn flush(&self, marker: DataMarkerInfo, metadata: FlushMetadata) -> Result<(), DataError> {
93         (**self).flush(marker, metadata)
94     }
95 
close(&mut self) -> Result<ExporterCloseMetadata, DataError>96     fn close(&mut self) -> Result<ExporterCloseMetadata, DataError> {
97         (**self).close()
98     }
99 }
100 
101 /// A [`DynamicDataProvider`] that can be used for exporting data.
102 ///
103 /// Use [`make_exportable_provider`] to implement this.
104 pub trait ExportableProvider:
105     crate::data_provider::IterableDynamicDataProvider<ExportMarker> + Sync
106 {
107     /// Returns the set of supported markers
supported_markers(&self) -> BTreeSet<DataMarkerInfo>108     fn supported_markers(&self) -> BTreeSet<DataMarkerInfo>;
109 }
110 
111 impl ExportableProvider for Box<dyn ExportableProvider> {
supported_markers(&self) -> BTreeSet<DataMarkerInfo>112     fn supported_markers(&self) -> BTreeSet<DataMarkerInfo> {
113         (**self).supported_markers()
114     }
115 }
116 
117 /// This macro can be used on a data provider to allow it to be exported by `ExportDriver`.
118 ///
119 /// Data generation 'compiles' data by using this data provider (which usually translates data from
120 /// different sources and doesn't have to be efficient) to generate data structs, and then writing
121 /// them to an efficient format like `BlobDataProvider` or `BakedDataProvider`. The requirements
122 /// for `make_exportable_provider` are:
123 /// * The data struct has to implement [`serde::Serialize`](::serde::Serialize) and [`databake::Bake`]
124 /// * The provider needs to implement [`IterableDataProvider`] for all specified [`DataMarker`]s.
125 ///   This allows the generating code to know which [`DataIdentifierCow`]s to export.
126 #[macro_export]
127 #[doc(hidden)] // macro
128 macro_rules! __make_exportable_provider {
129     ($provider:ty, [ $($(#[$cfg:meta])? $struct_m:ty),+, ]) => {
130         impl $crate::export::ExportableProvider for $provider {
131             fn supported_markers(&self) -> alloc::collections::BTreeSet<$crate::DataMarkerInfo> {
132                 alloc::collections::BTreeSet::from_iter([
133                     $(
134                         $(#[$cfg])?
135                         <$struct_m>::INFO,
136                     )+
137                 ])
138             }
139         }
140 
141         $crate::dynutil::impl_dynamic_data_provider!(
142             $provider,
143             [ $($(#[$cfg])? $struct_m),+, ],
144             $crate::export::ExportMarker
145         );
146 
147         $crate::dynutil::impl_iterable_dynamic_data_provider!(
148             $provider,
149             [ $($(#[$cfg])? $struct_m),+, ],
150             $crate::export::ExportMarker
151         );
152     };
153 }
154 #[doc(inline)]
155 pub use __make_exportable_provider as make_exportable_provider;
156 
157 /// A `DataExporter` that forks to multiple `DataExporter`s.
158 #[derive(Default)]
159 pub struct MultiExporter(Vec<Box<dyn DataExporter>>);
160 
161 impl MultiExporter {
162     /// Creates a `MultiExporter` for the given exporters.
new(exporters: Vec<Box<dyn DataExporter>>) -> Self163     pub const fn new(exporters: Vec<Box<dyn DataExporter>>) -> Self {
164         Self(exporters)
165     }
166 }
167 
168 impl core::fmt::Debug for MultiExporter {
fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result169     fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result {
170         f.debug_struct("MultiExporter")
171             .field("0", &format!("vec[len = {}]", self.0.len()))
172             .finish()
173     }
174 }
175 
176 impl DataExporter for MultiExporter {
put_payload( &self, marker: DataMarkerInfo, id: DataIdentifierBorrowed, payload: &DataPayload<ExportMarker>, ) -> Result<(), DataError>177     fn put_payload(
178         &self,
179         marker: DataMarkerInfo,
180         id: DataIdentifierBorrowed,
181         payload: &DataPayload<ExportMarker>,
182     ) -> Result<(), DataError> {
183         self.0
184             .iter()
185             .try_for_each(|e| e.put_payload(marker, id, payload))
186     }
187 
flush_singleton( &self, marker: DataMarkerInfo, payload: &DataPayload<ExportMarker>, metadata: FlushMetadata, ) -> Result<(), DataError>188     fn flush_singleton(
189         &self,
190         marker: DataMarkerInfo,
191         payload: &DataPayload<ExportMarker>,
192         metadata: FlushMetadata,
193     ) -> Result<(), DataError> {
194         self.0
195             .iter()
196             .try_for_each(|e| e.flush_singleton(marker, payload, metadata))
197     }
198 
flush(&self, marker: DataMarkerInfo, metadata: FlushMetadata) -> Result<(), DataError>199     fn flush(&self, marker: DataMarkerInfo, metadata: FlushMetadata) -> Result<(), DataError> {
200         self.0.iter().try_for_each(|e| e.flush(marker, metadata))
201     }
202 
close(&mut self) -> Result<ExporterCloseMetadata, DataError>203     fn close(&mut self) -> Result<ExporterCloseMetadata, DataError> {
204         Ok(ExporterCloseMetadata(Some(Box::new(
205             self.0.iter_mut().try_fold(vec![], |mut m, e| {
206                 m.push(e.close()?.0);
207                 Ok::<_, DataError>(m)
208             })?,
209         ))))
210     }
211 }
212