Skip to main content

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;