ferroui_base/media/text_formatting/text_run.rs
1use std::any::Any;
2use std::rc::Rc;
3
4use crate::media::text_formatting::{DrawableTextRun, TextEndOfLine, TextRunProperties};
5use crate::utilities::ReadOnlyMemory;
6
7/// The default length of a text run in the text source (one position).
8pub const DEFAULT_TEXT_SOURCE_LENGTH: i32 = 1;
9
10/// Represents a portion of a text line object.
11///
12/// Upstream `TextRun` is an abstract class whose subclasses are tested with
13/// `is`/`as`. Here it is a trait: runs are handled as `Rc<dyn TextRun>` and
14/// recovered with [`dyn TextRun::downcast_ref`] / [`dyn TextRun::downcast_rc`],
15/// or with the `as_*` hooks for the open base classes (`DrawableTextRun`,
16/// `TextEndOfLine`).
17pub trait TextRun: 'static {
18 /// Gets the text source length (UTF-16 code units).
19 fn length(&self) -> i32 {
20 DEFAULT_TEXT_SOURCE_LENGTH
21 }
22
23 /// Gets the text run's text.
24 fn text(&self) -> ReadOnlyMemory<u16> {
25 ReadOnlyMemory::empty()
26 }
27
28 /// Gets the text run's text as a slice. Runs with text override this
29 /// together with [`TextRun::text`]; hot paths read the slice.
30 fn text_span(&self) -> &[u16] {
31 &[]
32 }
33
34 /// A set of properties shared by every character in the run.
35 fn properties(&self) -> Option<&Rc<dyn TextRunProperties>> {
36 None
37 }
38
39 /// The run as a drawable run (C# `run is DrawableTextRun`).
40 fn as_drawable(&self) -> Option<&dyn DrawableTextRun> {
41 None
42 }
43
44 /// The run as an end of line marker (C# `run is TextEndOfLine`).
45 fn as_text_end_of_line(&self) -> Option<&TextEndOfLine> {
46 None
47 }
48
49 /// The run as [`Any`], for downcasting to a concrete run type.
50 fn as_any(&self) -> &dyn Any;
51
52 /// The run handle as [`Any`], for downcasting to a concrete run handle.
53 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any>;
54}
55
56impl dyn TextRun {
57 /// C# `run as T` for a concrete run type.
58 #[inline]
59 pub fn downcast_ref<T: TextRun>(&self) -> Option<&T> {
60 self.as_any().downcast_ref::<T>()
61 }
62
63 /// C# `run is T` for a concrete run type.
64 #[inline]
65 pub fn is<T: TextRun>(&self) -> bool {
66 self.as_any().is::<T>()
67 }
68
69 /// C# `run as T` for a concrete run type, keeping the handle.
70 pub fn downcast_rc<T: TextRun>(self: Rc<Self>) -> Option<Rc<T>> {
71 if self.as_any().is::<T>() {
72 self.into_any_rc().downcast::<T>().ok()
73 } else {
74 None
75 }
76 }
77}
78
79/// Implements the two `Any` accessors of [`TextRun`] inside an `impl TextRun for T` block.
80#[macro_export]
81#[doc(hidden)]
82macro_rules! __text_run_any {
83 () => {
84 #[inline]
85 fn as_any(&self) -> &dyn ::std::any::Any {
86 self
87 }
88
89 #[inline]
90 fn into_any_rc(self: ::std::rc::Rc<Self>) -> ::std::rc::Rc<dyn ::std::any::Any> {
91 self
92 }
93 };
94}
95
96pub use crate::__text_run_any as text_run_any;