umsh_text/
owned.rs

1//! Allocated convenience types (feature `alloc`).
2//!
3//! The borrowed [`TextMessage`] is the canonical representation; these types
4//! exist for callers that want to hold messages beyond the life of a receive
5//! buffer.
6
7use alloc::string::String;
8use alloc::vec::Vec;
9
10use crate::model::{ExtensionOptions, MessageSequence, MessageType, Regarding, TextMessage};
11
12/// Owned copy of a message's extension-option block.
13#[derive(Clone, Debug, Default, PartialEq, Eq)]
14pub struct OwnedExtensionOptions {
15    base_number: u16,
16    data: Vec<u8>,
17}
18
19impl OwnedExtensionOptions {
20    pub fn is_empty(&self) -> bool {
21        self.data.is_empty()
22    }
23
24    pub fn as_borrowed(&self) -> ExtensionOptions<'_> {
25        ExtensionOptions {
26            base_number: self.base_number,
27            data: &self.data,
28        }
29    }
30}
31
32impl From<ExtensionOptions<'_>> for OwnedExtensionOptions {
33    fn from(value: ExtensionOptions<'_>) -> Self {
34        Self {
35            base_number: value.base_number,
36            data: value.data.into(),
37        }
38    }
39}
40
41/// Owned counterpart of [`TextMessage`].
42#[derive(Clone, Debug, PartialEq, Eq)]
43pub struct OwnedTextMessage {
44    pub message_type: MessageType,
45    pub sender_handle: Option<String>,
46    pub sequence: Option<MessageSequence>,
47    pub sequence_reset: bool,
48    pub regarding: Option<Regarding>,
49    pub editing: Option<u8>,
50    pub bg_color: Option<[u8; 3]>,
51    pub text_color: Option<[u8; 3]>,
52    pub channel_group_resend: bool,
53    pub extensions: OwnedExtensionOptions,
54    pub body: Vec<u8>,
55}
56
57impl OwnedTextMessage {
58    /// A basic text message with the given body and no options.
59    pub fn basic(body: impl Into<String>) -> Self {
60        Self::from(TextMessage::basic(&body.into()))
61    }
62
63    pub fn as_borrowed(&self) -> TextMessage<'_> {
64        TextMessage {
65            message_type: self.message_type,
66            sender_handle: self.sender_handle.as_deref(),
67            sequence: self.sequence,
68            sequence_reset: self.sequence_reset,
69            regarding: self.regarding,
70            editing: self.editing,
71            bg_color: self.bg_color,
72            text_color: self.text_color,
73            channel_group_resend: self.channel_group_resend,
74            extensions: self.extensions.as_borrowed(),
75            body: &self.body,
76        }
77    }
78
79    /// The body as UTF-8 text, when valid.
80    pub fn body_str(&self) -> Option<&str> {
81        core::str::from_utf8(&self.body).ok()
82    }
83}
84
85impl From<TextMessage<'_>> for OwnedTextMessage {
86    fn from(value: TextMessage<'_>) -> Self {
87        Self {
88            message_type: value.message_type,
89            sender_handle: value.sender_handle.map(String::from),
90            sequence: value.sequence,
91            sequence_reset: value.sequence_reset,
92            regarding: value.regarding,
93            editing: value.editing,
94            bg_color: value.bg_color,
95            text_color: value.text_color,
96            channel_group_resend: value.channel_group_resend,
97            extensions: value.extensions.into(),
98            body: value.body.into(),
99        }
100    }
101}