summaryrefslogtreecommitdiffstats
path: root/vendor/icu_provider/src/datagen/mod.rs
blob: e52a19c4d2a1a20f54a11042caacace0033a1bd6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

//! This module contains various utilities required to generate ICU4X data files, typically
//! via the `icu_datagen` reference crate. End users should not need to consume anything in
//! this module as a library unless defining new types that integrate with `icu_datagen`.
//!
//! This module can be enabled with the `datagen` Cargo feature on `icu_provider`.

mod data_conversion;
mod heap_measure;
mod iter;
mod payload;
pub use data_conversion::DataConverter;
pub use heap_measure::{HeapStats, HeapStatsMarker};
pub use iter::IterableDataProvider;

#[doc(hidden)] // exposed for make_exportable_provider
pub use iter::IterableDynamicDataProvider;
#[doc(hidden)] // exposed for make_exportable_provider
pub use payload::{ExportBox, ExportMarker};

use crate::prelude::*;

/// An object capable of exporting data payloads in some form.
pub trait DataExporter: Sync {
    /// Save a `payload` corresponding to the given key and locale.
    /// Takes non-mut self as it can be called concurrently.
    fn put_payload(
        &self,
        key: DataKey,
        locale: &DataLocale,
        payload: &DataPayload<ExportMarker>,
    ) -> Result<(), DataError>;

    /// Function called after all keys have been fully dumped.
    /// Takes non-mut self as it can be called concurrently.
    fn flush(&self, _key: DataKey) -> Result<(), DataError> {
        Ok(())
    }

    /// This function has to be called before the object is dropped (after all
    /// keys have been fully dumped). This conceptually takes ownership, so
    /// clients *may not* interact with this object after close has been called.
    fn close(&mut self) -> Result<(), DataError> {
        Ok(())
    }
}

/// A [`DynamicDataProvider`] that can be used for exporting data.
///
/// Use [`make_exportable_provider`] to implement this.
pub trait ExportableProvider: IterableDynamicDataProvider<ExportMarker> + Sync {}
impl<T> ExportableProvider for T where T: IterableDynamicDataProvider<ExportMarker> + Sync {}

/// This macro can be used on a data provider to allow it to be used for data generation.
///
/// Data generation 'compiles' data by using this data provider (which usually translates data from
/// different sources and doesn't have to be efficient) to generate data structs, and then writing
/// them to an efficient format like [`BlobDataProvider`] or [`BakedDataProvider`]. The requirements
/// for `make_exportable_provider` are:
/// * The data struct has to implement [`serde::Serialize`](::serde::Serialize) and [`databake::Bake`]
/// * The provider needs to implement [`IterableDataProvider`] for all specified [`KeyedDataMarker`]s.
///   This allows the generating code to know which [`DataLocale`] to collect.
///
/// [`BlobDataProvider`]: ../../icu_provider_blob/struct.BlobDataProvider.html
/// [`BakedDataProvider`]: ../../icu_datagen/index.html
#[macro_export]
macro_rules! make_exportable_provider {
    ($provider:ty, [ $($struct_m:ident),+, ]) => {
        $crate::impl_dynamic_data_provider!(
            $provider,
            [ $($struct_m),+, ],
            $crate::datagen::ExportMarker
        );
        $crate::impl_dynamic_data_provider!(
            $provider,
            [ $($struct_m),+, ],
            $crate::any::AnyMarker
        );

        impl $crate::datagen::IterableDynamicDataProvider<$crate::datagen::ExportMarker> for $provider {
            fn supported_locales_for_key(&self, key: $crate::DataKey) -> Result<Vec<$crate::DataLocale>, $crate::DataError> {
                #![allow(non_upper_case_globals)]
                // Reusing the struct names as identifiers
                $(
                    const $struct_m: $crate::DataKeyHash = <$struct_m as $crate::KeyedDataMarker>::KEY.hashed();
                )+
                match key.hashed() {
                    $(
                        $struct_m => {
                            $crate::datagen::IterableDataProvider::<$struct_m>::supported_locales(self)
                        }
                    )+,
                    _ => Err($crate::DataErrorKind::MissingDataKey.with_key(key))
                }
            }
        }

        impl $crate::datagen::DataConverter<$crate::buf::BufferMarker, $crate::datagen::HeapStatsMarker> for $provider {
            fn convert(&self, key: $crate::DataKey, from: $crate::DataPayload<$crate::buf::BufferMarker>) -> Result<$crate::DataPayload<$crate::datagen::HeapStatsMarker>, ($crate::DataPayload<$crate::buf::BufferMarker>, $crate::DataError)> {
                #![allow(non_upper_case_globals)]
                // Reusing the struct names as identifiers
                $(
                    const $struct_m: $crate::DataKeyHash = <$struct_m as $crate::KeyedDataMarker>::KEY.hashed();
                )+
                match key.hashed() {
                    $(
                        $struct_m => {
                            let heap_stats = from.attempt_zero_copy_heap_size::<$struct_m>();
                            return Ok($crate::DataPayload::from_owned(heap_stats));
                        }
                    )+,
                    _ => Err((from, $crate::DataErrorKind::MissingDataKey.with_key(key)))
                }
            }
        }
    };
}