1//! Defines `MessageView` trait.
2
3use std::borrow::{Borrow, ToOwned};
4use std::error::Error;
5use std::fmt::{Display, Formatter};
6
7use crate::message::{Message, MessageFlags};
8
9/// Error type when trying to access a field that is not applicable to the plural type of the message.
10#[derive(Debug)]
11pub struct SingularPluralMismatchError;
12
13impl Display for SingularPluralMismatchError {
14 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
15 write!(f, "singular/plural type mismatch")
16 }
17}
18
19impl Error for SingularPluralMismatchError {}
20
21/// Immutable view of a `Message`.
22pub trait MessageView {
23 /// Is this message singular?
24 fn is_singular(&self) -> bool;
25
26 /// Is this message plural?
27 fn is_plural(&self) -> bool;
28
29 /// Is this message translated?
30 fn is_translated(&self) -> bool;
31
32 /// Is this message fuzzy?
33 fn is_fuzzy(&self) -> bool;
34
35 /// Get comments field of the message.
36 fn comments(&self) -> &str;
37
38 /// Get source code location field of the message.
39 fn source(&self) -> &str;
40
41 /// Get flags field of the message.
42 fn flags(&self) -> &MessageFlags;
43
44 /// Get context field of the message.
45 fn msgctxt(&self) -> &str;
46
47 /// Get msgid field of the message.
48 fn msgid(&self) -> &str;
49
50 /// Get msgid_plural field of the message, or error if this is not a plural message.
51 fn msgid_plural(&self) -> Result<&str, SingularPluralMismatchError>;
52
53 /// Get msgstr field of the message, or error if this is not a singular message.
54 fn msgstr(&self) -> Result<&str, SingularPluralMismatchError>;
55
56 /// Get msgstr_plural field of the message, or error if this is not a plural message.
57 fn msgstr_plural(&self) -> Result<&Vec<String>, SingularPluralMismatchError>;
58}
59
60/// Mutable view of a `Message`.
61pub trait MessageMutView: MessageView {
62 /// Get a mutable reference to the comments field of the message.
63 fn comments_mut(&mut self) -> &mut String;
64
65 /// Get a mutable reference to the source code location field of the message.
66 fn source_mut(&mut self) -> &mut String;
67
68 /// Get a mutable reference to the flags field of the message.
69 fn flags_mut(&mut self) -> &mut MessageFlags;
70
71 /// Set the context field of the message.
72 fn set_msgctxt(&mut self, msgctxt: String);
73
74 /// Set the msgid field of the message.
75 fn set_msgid(&mut self, msgid: String);
76
77 /// Set the msgid_plural field of the message, or error if this is not a plural message.
78 fn set_msgid_plural(&mut self, msgid_plural: String)
79 -> Result<(), SingularPluralMismatchError>;
80
81 /// Set the msgstr field of the message, or error if this is not a singular message.
82 fn set_msgstr(&mut self, msgstr: String) -> Result<(), SingularPluralMismatchError>;
83
84 /// Get a mutable reference to the msgstr field of the message, or error if this is not a singular message.
85 fn msgstr_mut(&mut self) -> Result<&mut String, SingularPluralMismatchError>;
86
87 /// Get a mutable reference to the msgstr_plural field of the message, or error if this is not a plural message.
88 fn msgstr_plural_mut(&mut self) -> Result<&mut Vec<String>, SingularPluralMismatchError>;
89}
90
91/// Mutable view of a `Message` that is part of a catalog.
92pub trait CatalogMessageMutView: MessageMutView {
93 /// Delete this message from the catalog.
94 /// It is undefined behavior to continue access the message object through this proxy afterwards.
95 fn delete(&mut self);
96
97 /// Detach this message from the catalog and get the message object back.
98 /// It is undefined behavior to continue access the message object through this proxy afterwards.
99 fn detach(&mut self) -> Message;
100}
101
102impl MessageView for Message {
103 fn is_singular(&self) -> bool {
104 !self.is_plural
105 }
106
107 fn is_plural(&self) -> bool {
108 self.is_plural
109 }
110
111 fn is_translated(&self) -> bool {
112 if self.is_plural {
113 self.msgstr_plural.iter().all(|x| !x.is_empty())
114 } else {
115 !self.msgstr.is_empty()
116 }
117 }
118
119 fn is_fuzzy(&self) -> bool {
120 self.flags.is_fuzzy()
121 }
122
123 fn comments(&self) -> &str {
124 &self.comments
125 }
126
127 fn source(&self) -> &str {
128 &self.source
129 }
130
131 fn flags(&self) -> &MessageFlags {
132 &self.flags
133 }
134
135 fn msgctxt(&self) -> &str {
136 &self.msgctxt
137 }
138
139 fn msgid(&self) -> &str {
140 &self.msgid
141 }
142
143 fn msgid_plural(&self) -> Result<&str, SingularPluralMismatchError> {
144 if self.is_plural {
145 Ok(&self.msgid_plural)
146 } else {
147 Err(SingularPluralMismatchError)
148 }
149 }
150
151 fn msgstr(&self) -> Result<&str, SingularPluralMismatchError> {
152 if self.is_plural {
153 Err(SingularPluralMismatchError)
154 } else {
155 Ok(&self.msgstr)
156 }
157 }
158
159 fn msgstr_plural(&self) -> Result<&Vec<String>, SingularPluralMismatchError> {
160 if self.is_plural {
161 Ok(&self.msgstr_plural)
162 } else {
163 Err(SingularPluralMismatchError)
164 }
165 }
166}
167
168impl MessageMutView for Message {
169 fn comments_mut(&mut self) -> &mut String {
170 &mut self.comments
171 }
172
173 fn source_mut(&mut self) -> &mut String {
174 &mut self.source
175 }
176
177 fn flags_mut(&mut self) -> &mut MessageFlags {
178 &mut self.flags
179 }
180
181 fn set_msgctxt(&mut self, msgctxt: String) {
182 self.msgctxt = msgctxt
183 }
184
185 fn set_msgid(&mut self, msgid: String) {
186 self.msgid = msgid
187 }
188
189 fn set_msgid_plural(
190 &mut self,
191 msgid_plural: String,
192 ) -> Result<(), SingularPluralMismatchError> {
193 if self.is_plural() {
194 self.msgid_plural = msgid_plural;
195 Ok(())
196 } else {
197 Err(SingularPluralMismatchError)
198 }
199 }
200
201 fn set_msgstr(&mut self, msgstr: String) -> Result<(), SingularPluralMismatchError> {
202 if self.is_singular() {
203 self.msgstr = msgstr;
204 Ok(())
205 } else {
206 Err(SingularPluralMismatchError)
207 }
208 }
209
210 fn msgstr_mut(&mut self) -> Result<&mut String, SingularPluralMismatchError> {
211 if self.is_singular() {
212 Ok(&mut self.msgstr)
213 } else {
214 Err(SingularPluralMismatchError)
215 }
216 }
217
218 fn msgstr_plural_mut(&mut self) -> Result<&mut Vec<String>, SingularPluralMismatchError> {
219 if self.is_plural() {
220 Ok(&mut self.msgstr_plural)
221 } else {
222 Err(SingularPluralMismatchError)
223 }
224 }
225}
226
227impl<'a> Borrow<dyn MessageView + 'a> for Message {
228 fn borrow(&self) -> &(dyn MessageView + 'a) {
229 self
230 }
231}
232
233impl ToOwned for dyn MessageView {
234 type Owned = Message;
235
236 fn to_owned(&self) -> Self::Owned {
237 if self.is_singular() {
238 Self::Owned {
239 comments: self.comments().to_string(),
240 source: self.source().to_string(),
241 flags: self.flags().clone(),
242 msgctxt: self.msgctxt().to_string(),
243 msgid: self.msgid().to_string(),
244 msgid_plural: String::default(),
245 msgstr: self.msgstr().unwrap().to_string(),
246 msgstr_plural: vec![],
247 is_plural: false,
248 }
249 } else {
250 Self::Owned {
251 comments: self.comments().to_string(),
252 source: self.source().to_string(),
253 flags: self.flags().clone(),
254 msgctxt: self.msgctxt().to_string(),
255 msgid: self.msgid().to_string(),
256 msgid_plural: self.msgid_plural().unwrap().to_string(),
257 msgstr: String::default(),
258 msgstr_plural: self.msgstr_plural().unwrap().to_owned(),
259 is_plural: true,
260 }
261 }
262 }
263}
264