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