resb/
bundle.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//! The `bundle` module provides data structures for working directly with the
6//! contents of a resource bundle.
7//!
8//! WARNING: This module is not suitable for use at runtime due to its reliance
9//! on `std` and `alloc` and therefore not intended for general deserialization
10//! of resource bundles. Rather, it is intended to be used in development-time
11//! tools for working with bundles.
12
13extern crate alloc;
14use alloc::{borrow::Cow, collections::BTreeMap};
15
16use crate::MASK_28_BIT;
17
18/// A tree-like collection of data [`Resource`]s primarily intended for storing
19/// locale and other internationalization data for [ICU] (International
20/// Components for Unicode).
21///
22/// [ICU]: https://icu.unicode.org/
23#[derive(Debug)]
24pub struct ResourceBundle<'a> {
25    name: Cow<'a, str>,
26    root: Resource<'a>,
27
28    /// Whether fallback is enabled for this resource bundle.
29    ///
30    /// A resource bundle storing locale data may omit some data in order to
31    /// reduce duplication, allowing fallback to more general locales which
32    /// use the same values.
33    pub is_locale_fallback_enabled: bool,
34}
35
36impl<'a> ResourceBundle<'a> {
37    /// Makes a new resource bundle with the specified resource at its root.
38    pub fn new(name: Cow<'a, str>, root: Resource<'a>, is_locale_fallback_enabled: bool) -> Self {
39        Self {
40            name,
41            root,
42            is_locale_fallback_enabled,
43        }
44    }
45
46    /// Gets the name of the resource bundle.
47    ///
48    /// This name is used as the "key" of the root resource in a text format
49    /// bundle, but is not used in building binary resource bundles.
50    pub fn name(&self) -> &str {
51        &self.name
52    }
53
54    /// Gets the root resource in the resource tree.
55    pub fn root(&self) -> &Resource {
56        &self.root
57    }
58}
59
60/// A data resource within a [`ResourceBundle`].
61#[derive(Debug)]
62#[non_exhaustive]
63pub enum Resource<'a> {
64    /// A well-formed UTF-8 string.
65    String(Cow<'a, str>),
66
67    /// A heterogeneous list of resources, ordered by insertion.
68    Array(Vec<Resource<'a>>),
69
70    /// A set of key-resource pairs, sorted lexically by key.
71    Table(Table<'a>),
72
73    /// A slice of arbitrary binary data.
74    Binary(Cow<'a, [u8]>),
75
76    /// A 28-bit integer.
77    ///
78    /// May be interpreted as either signed or unsigned depending on consumer
79    /// expectations. See [`Int28`] for further details.
80    Integer(Int28),
81
82    /// A list of 32-bit integers, ordered by insertion.
83    IntVector(Vec<u32>),
84}
85
86/// A table of [`Resource`]s indexed by a string-based [`Key`].
87// Ordering of keys in a table is significant, so `HashMap` isn't appropriate
88// here.
89pub type Table<'a> = BTreeMap<Key<'a>, Resource<'a>>;
90
91/// A key for a [`Resource`] within a [`Table`].
92#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
93pub struct Key<'a>(Cow<'a, str>);
94
95impl Key<'_> {
96    /// Converts the string representing the key into a slice of UTF-8 bytes.
97    pub fn as_bytes(&self) -> &[u8] {
98        self.0.as_bytes()
99    }
100}
101
102impl<'a> From<&'a str> for Key<'a> {
103    fn from(value: &'a str) -> Self {
104        Self(Cow::from(value))
105    }
106}
107
108impl From<String> for Key<'_> {
109    fn from(value: String) -> Self {
110        Self(Cow::from(value))
111    }
112}
113
114impl<'a> From<Key<'a>> for String {
115    fn from(value: Key<'a>) -> Self {
116        value.0.into_owned()
117    }
118}
119
120/// A 28-bit integer of undetermined signedness.
121///
122/// [`Resource`]s may include 28-bit integers whose signedness is determined at
123/// runtime by consumers. Because these integers are stored in a 32-bit value,
124/// negative values in signed integers require special handling, provided by
125/// this newtype wrapper.
126#[derive(Copy, Clone, Debug, PartialEq)]
127pub struct Int28(u32);
128
129impl From<Int28> for i32 {
130    fn from(value: Int28) -> Self {
131        ((value.0 as i32) << 4) >> 4
132    }
133}
134
135impl From<Int28> for u32 {
136    fn from(value: Int28) -> Self {
137        value.0
138    }
139}
140
141impl From<i32> for Int28 {
142    fn from(value: i32) -> Self {
143        Self::from(value as u32)
144    }
145}
146
147impl From<u32> for Int28 {
148    fn from(value: u32) -> Self {
149        Self(value & MASK_28_BIT)
150    }
151}