1#[diplomat::bridge]
6#[diplomat::abi_rename = "icu4x_{0}_mv1"]
7pub mod ffi {
8 use alloc::boxed::Box;
9 use alloc::vec::Vec;
10 use core::fmt::Write;
11
12 #[cfg(feature = "buffer_provider")]
13 use crate::unstable::{errors::ffi::DataError, provider::ffi::DataProvider};
14
15 #[non_exhaustive]
16 #[diplomat::rust_link(unicode_bidi::Direction, Enum)]
17 pub enum BidiDirection {
18 #[diplomat::attr(auto, default)]
21 Ltr,
22 Rtl,
23 Mixed,
24 }
25
26 #[diplomat::opaque]
27 #[diplomat::rust_link(icu::properties::props::BidiClass, Struct)]
29 #[diplomat::attr(demo_gen, disable)] pub struct Bidi(pub icu_properties::CodePointMapData<icu_properties::props::BidiClass>);
31
32 impl Bidi {
33 #[diplomat::attr(auto, constructor)]
35 #[cfg(feature = "compiled_data")]
36 pub fn create() -> Box<Bidi> {
37 Box::new(Bidi(
38 icu_properties::CodePointMapData::new().static_to_owned(),
39 ))
40 }
41
42 #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor = "with_provider")]
44 #[cfg(feature = "buffer_provider")]
45 pub fn create_with_provider(provider: &DataProvider) -> Result<Box<Bidi>, DataError> {
46 Ok(Box::new(Bidi(
47 icu_properties::CodePointMapData::try_new_unstable(&provider.get_unstable()?)?,
48 )))
49 }
50 #[diplomat::rust_link(unicode_bidi::BidiInfo::new_with_data_source, FnInStruct)]
56 #[diplomat::rust_link(
57 icu::properties::CodePointMapDataBorrowed::bidi_class,
58 FnInStruct,
59 hidden
60 )]
61 #[diplomat::attr(not(supports = utf8_strings), disable)]
62 #[diplomat::attr(*, rename = "for_text")]
63 pub fn for_text_utf8<'text>(
64 &self,
65 text: &'text DiplomatStr,
66 default_level: Option<u8>,
67 ) -> Option<Box<BidiInfo<'text>>> {
68 let text = core::str::from_utf8(text).ok()?;
69
70 Some(Box::new(BidiInfo(
71 unicode_bidi::BidiInfo::new_with_data_source(
72 &self.0.as_borrowed(),
73 text,
74 default_level.and_then(|l| unicode_bidi::Level::new(l).ok()),
75 ),
76 )))
77 }
78
79 #[diplomat::rust_link(unicode_bidi::BidiInfo::new_with_data_source, FnInStruct)]
83 #[diplomat::rust_link(
84 icu::properties::CodePointMapDataBorrowed::bidi_class,
85 FnInStruct,
86 hidden
87 )]
88 #[diplomat::attr(supports = utf8_strings, disable)]
90 #[diplomat::attr(supports = utf16_strings, rename = "for_text")]
91 pub fn for_text_valid_utf8<'text>(
92 &self,
93 text: &'text str,
94 default_level: Option<u8>,
95 ) -> Box<BidiInfo<'text>> {
96 Box::new(BidiInfo(unicode_bidi::BidiInfo::new_with_data_source(
97 &self.0.as_borrowed(),
98 text,
99 default_level.and_then(|l| unicode_bidi::Level::new(l).ok()),
100 )))
101 }
102
103 #[diplomat::rust_link(unicode_bidi::BidiInfo::reorder_visual, FnInStruct)]
112 pub fn reorder_visual(&self, levels: &[u8]) -> Box<ReorderedIndexMap> {
113 let levels = unicode_bidi::Level::from_slice_unchecked(levels);
114 Box::new(ReorderedIndexMap(unicode_bidi::BidiInfo::reorder_visual(
115 levels,
116 )))
117 }
118
119 #[diplomat::rust_link(unicode_bidi::level::Level::is_rtl, FnInStruct)]
123 pub fn level_is_rtl(level: u8) -> bool {
124 unicode_bidi::Level::new(level)
125 .unwrap_or_else(|_| unicode_bidi::Level::ltr())
126 .is_rtl()
127 }
128
129 #[diplomat::rust_link(unicode_bidi::level::Level::is_ltr, FnInStruct)]
133 pub fn level_is_ltr(level: u8) -> bool {
134 unicode_bidi::Level::new(level)
135 .unwrap_or_else(|_| unicode_bidi::Level::ltr())
136 .is_ltr()
137 }
138
139 #[diplomat::rust_link(unicode_bidi::level::Level::rtl, FnInStruct)]
141 pub fn level_rtl() -> u8 {
142 unicode_bidi::Level::rtl().number()
143 }
144
145 #[diplomat::rust_link(unicode_bidi::level::Level::ltr, FnInStruct)]
147 pub fn level_ltr() -> u8 {
148 unicode_bidi::Level::ltr().number()
149 }
150 }
151
152 #[diplomat::opaque]
158 #[diplomat::attr(demo_gen, disable)] pub struct ReorderedIndexMap(pub Vec<usize>);
160
161 impl ReorderedIndexMap {
162 #[diplomat::attr(auto, getter)]
164 pub fn as_slice<'a>(&'a self) -> &'a [usize] {
165 &self.0
166 }
167
168 #[diplomat::attr(auto, getter = "length")]
170 pub fn len(&self) -> usize {
171 self.0.len()
172 }
173
174 #[diplomat::attr(auto, getter)]
176 pub fn is_empty(&self) -> bool {
177 self.0.is_empty()
178 }
179
180 #[diplomat::attr(auto, indexer)]
184 pub fn get(&self, index: usize) -> usize {
185 self.0.get(index).copied().unwrap_or(0)
186 }
187 }
188
189 #[diplomat::rust_link(unicode_bidi::BidiInfo, Struct)]
191 #[diplomat::opaque]
192 #[diplomat::attr(demo_gen, disable)] pub struct BidiInfo<'text>(pub unicode_bidi::BidiInfo<'text>);
194
195 impl<'text> BidiInfo<'text> {
196 #[diplomat::attr(auto, getter)]
198 pub fn paragraph_count(&self) -> usize {
199 self.0.paragraphs.len()
200 }
201
202 pub fn paragraph_at(&'text self, n: usize) -> Option<Box<BidiParagraph<'text>>> {
204 self.0
205 .paragraphs
206 .get(n)
207 .map(|p| Box::new(BidiParagraph(unicode_bidi::Paragraph::new(&self.0, p))))
208 }
209
210 #[diplomat::attr(auto, getter)]
212 pub fn size(&self) -> usize {
213 self.0.levels.len()
214 }
215
216 pub fn level_at(&self, pos: usize) -> u8 {
222 if let Some(l) = self.0.levels.get(pos) {
223 l.number()
224 } else {
225 0
226 }
227 }
228 }
229
230 #[diplomat::opaque]
232 #[diplomat::attr(demo_gen, disable)] pub struct BidiParagraph<'info>(pub unicode_bidi::Paragraph<'info, 'info>);
234
235 impl<'info> BidiParagraph<'info> {
236 pub fn set_paragraph_in_text(&mut self, n: usize) -> bool {
242 let Some(para) = self.0.info.paragraphs.get(n) else {
243 return false;
244 };
245 self.0 = unicode_bidi::Paragraph::new(self.0.info, para);
246 true
247 }
248
249 #[diplomat::rust_link(unicode_bidi::Paragraph::level_at, FnInStruct)]
250 #[diplomat::attr(auto, getter)]
251 pub fn direction(&self) -> BidiDirection {
253 self.0.direction().into()
254 }
255
256 #[diplomat::rust_link(unicode_bidi::ParagraphInfo::len, FnInStruct)]
258 #[diplomat::attr(auto, getter)]
259 pub fn size(&self) -> usize {
260 self.0.para.len()
261 }
262
263 #[diplomat::attr(auto, getter)]
265 pub fn range_start(&self) -> usize {
266 self.0.para.range.start
267 }
268
269 #[diplomat::attr(auto, getter)]
271 pub fn range_end(&self) -> usize {
272 self.0.para.range.end
273 }
274
275 #[diplomat::rust_link(unicode_bidi::Paragraph::level_at, FnInStruct)]
278 #[diplomat::attr(demo_gen, disable)] pub fn reorder_line(
280 &self,
281 range_start: usize,
282 range_end: usize,
283 out: &mut DiplomatWrite,
284 ) -> Option<()> {
285 if range_start < self.range_start() || range_end > self.range_end() {
286 return None;
287 }
288
289 let info = self.0.info;
290 let para = self.0.para;
291
292 let reordered = info.reorder_line(para, range_start..range_end);
293
294 let _infallible = out.write_str(&reordered);
295
296 Some(())
297 }
298
299 #[diplomat::rust_link(unicode_bidi::Paragraph::level_at, FnInStruct)]
305 pub fn level_at(&self, pos: usize) -> u8 {
306 if pos >= self.size() {
307 return 0;
308 }
309
310 self.0.level_at(pos).number()
311 }
312 }
313}
314
315use unicode_bidi::Direction;
316
317impl From<Direction> for ffi::BidiDirection {
318 fn from(other: Direction) -> Self {
319 match other {
320 Direction::Ltr => Self::Ltr,
321 Direction::Rtl => Self::Rtl,
322 Direction::Mixed => Self::Mixed,
323 }
324 }
325}