Skip to main content

cranpose_ui/text/
shared_text.rs

1use std::{fmt, ops::Deref, rc::Rc};
2
3use super::AnnotatedString;
4use crate::widgets::text::{IntoTextSource, TextSource};
5
6/// Immutable text shared by widgets, localized results, and retained control labels.
7#[derive(Clone, Debug)]
8pub struct SharedText(Storage);
9
10#[derive(Clone, Debug)]
11enum Storage {
12    Static(&'static str),
13    Annotated(Rc<AnnotatedString>),
14}
15
16impl SharedText {
17    /// The plain text used by accessibility and native string APIs.
18    pub fn as_str(&self) -> &str {
19        match &self.0 {
20            Storage::Static(text) => text,
21            Storage::Annotated(text) => &text.text,
22        }
23    }
24}
25
26impl PartialEq for SharedText {
27    fn eq(&self, other: &Self) -> bool {
28        match (&self.0, &other.0) {
29            (Storage::Static(a), Storage::Static(b)) => a == b,
30            (Storage::Annotated(a), Storage::Annotated(b)) => Rc::ptr_eq(a, b) || a == b,
31            (Storage::Static(plain), Storage::Annotated(annotated))
32            | (Storage::Annotated(annotated), Storage::Static(plain)) => {
33                *plain == annotated.text
34                    && annotated.span_styles.is_empty()
35                    && annotated.paragraph_styles.is_empty()
36                    && annotated.string_annotations.is_empty()
37                    && annotated.link_annotations.is_empty()
38            }
39        }
40    }
41}
42
43impl From<String> for SharedText {
44    fn from(value: String) -> Self {
45        Self(Storage::Annotated(Rc::new(AnnotatedString::from(value))))
46    }
47}
48
49impl From<&'static str> for SharedText {
50    fn from(value: &'static str) -> Self {
51        Self(Storage::Static(value))
52    }
53}
54
55impl From<Rc<AnnotatedString>> for SharedText {
56    fn from(value: Rc<AnnotatedString>) -> Self {
57        Self(Storage::Annotated(value))
58    }
59}
60
61impl From<SharedText> for String {
62    fn from(value: SharedText) -> Self {
63        match value.0 {
64            Storage::Static(text) => text.to_owned(),
65            Storage::Annotated(shared) => match Rc::try_unwrap(shared) {
66                Ok(annotated) => annotated.text,
67                Err(shared) => shared.text.clone(),
68            },
69        }
70    }
71}
72
73impl Deref for SharedText {
74    type Target = str;
75    fn deref(&self) -> &str {
76        self.as_str()
77    }
78}
79
80impl AsRef<str> for SharedText {
81    fn as_ref(&self) -> &str {
82        self.as_str()
83    }
84}
85
86impl fmt::Display for SharedText {
87    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
88        formatter.write_str(self.as_str())
89    }
90}
91
92impl IntoTextSource for SharedText {
93    fn into_text_source(self) -> TextSource {
94        match self.0 {
95            Storage::Static(text) => text.into_text_source(),
96            Storage::Annotated(text) => TextSource::Static(text),
97        }
98    }
99}