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}