| 1 | //! Iterators over a Catalog. |
| 2 | |
| 3 | use crate::catalog::Catalog; |
| 4 | use crate::message::{ |
| 5 | CatalogMessageMutView, Message, MessageFlags, MessageKey, MessageMutView, MessageView, |
| 6 | SingularPluralMismatchError, |
| 7 | }; |
| 8 | |
| 9 | pub struct CatalogMessageRef<C> { |
| 10 | catalog: C, |
| 11 | index: usize, |
| 12 | } |
| 13 | |
| 14 | impl<C> CatalogMessageRef<C> { |
| 15 | fn begin(catalog: C) -> Self { |
| 16 | Self { catalog, index: 0 } |
| 17 | } |
| 18 | |
| 19 | fn at(catalog: C, index: usize) -> Self { |
| 20 | Self { catalog, index } |
| 21 | } |
| 22 | } |
| 23 | |
| 24 | /// An immutable iterator over messages in a catalog. |
| 25 | pub struct Iter<'a>(CatalogMessageRef<&'a Catalog>); |
| 26 | |
| 27 | impl<'a> Iter<'a> { |
| 28 | pub(crate) fn begin(catalog: &'a Catalog) -> Self { |
| 29 | Self(CatalogMessageRef::begin(catalog)) |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | impl<'a> Iterator for Iter<'a> { |
| 34 | type Item = &'a dyn MessageView; |
| 35 | |
| 36 | fn next(&mut self) -> Option<Self::Item> { |
| 37 | while self.0.index < self.0.catalog.messages.len() { |
| 38 | if let Some(m: &Message) = self.0.catalog.messages[self.0.index].as_ref() { |
| 39 | self.0.index += 1; |
| 40 | return Some(m); |
| 41 | } else { |
| 42 | self.0.index += 1 |
| 43 | } |
| 44 | } |
| 45 | None |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | /// A mutable iterator over messages in a catalog that allows mutating a message in-place. |
| 50 | pub struct IterMut<'a>(CatalogMessageRef<&'a mut Catalog>); |
| 51 | |
| 52 | impl<'a> IterMut<'a> { |
| 53 | pub(crate) fn begin(catalog: &'a mut Catalog) -> Self { |
| 54 | Self(CatalogMessageRef::begin(catalog)) |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | impl<'a> Iterator for IterMut<'a> { |
| 59 | type Item = MessageMutProxy<'a>; |
| 60 | |
| 61 | fn next(&mut self) -> Option<Self::Item> { |
| 62 | while self.0.index < self.0.catalog.messages.len() { |
| 63 | if self.0.catalog.messages[self.0.index].is_some() { |
| 64 | let current_index: usize = self.0.index; |
| 65 | self.0.index += 1; |
| 66 | return Some(MessageMutProxy::at( |
| 67 | catalog:unsafe { &mut *(self.0.catalog as *mut Catalog) }, |
| 68 | current_index, |
| 69 | )); |
| 70 | } else { |
| 71 | self.0.index += 1; |
| 72 | } |
| 73 | } |
| 74 | None |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | /// Proxy object for mutating a message that belongs to a catalog. |
| 79 | /// Mutating a message in a catalog has to go through this proxy object, otherwise modifying data |
| 80 | /// directly on the `Message` object may cause internal data inconsistencies in the catalog. |
| 81 | pub struct MessageMutProxy<'a>(CatalogMessageRef<&'a mut Catalog>); |
| 82 | |
| 83 | impl<'a> MessageMutProxy<'a> { |
| 84 | pub(crate) fn at(catalog: &'a mut Catalog, index: usize) -> Self { |
| 85 | Self(CatalogMessageRef::at(catalog, index)) |
| 86 | } |
| 87 | |
| 88 | fn message(&self) -> &Message { |
| 89 | self.0.catalog.messages[self.0.index].as_ref().unwrap() |
| 90 | } |
| 91 | |
| 92 | fn message_mut(&mut self) -> &mut Message { |
| 93 | self.0.catalog.messages[self.0.index].as_mut().unwrap() |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | impl<'a> MessageView for MessageMutProxy<'a> { |
| 98 | fn is_singular(&self) -> bool { |
| 99 | self.message().is_singular() |
| 100 | } |
| 101 | |
| 102 | fn is_plural(&self) -> bool { |
| 103 | self.message().is_plural() |
| 104 | } |
| 105 | |
| 106 | fn is_translated(&self) -> bool { |
| 107 | self.message().is_translated() |
| 108 | } |
| 109 | |
| 110 | fn is_fuzzy(&self) -> bool { |
| 111 | self.message().is_fuzzy() |
| 112 | } |
| 113 | |
| 114 | fn comments(&self) -> &str { |
| 115 | self.message().comments() |
| 116 | } |
| 117 | |
| 118 | fn source(&self) -> &str { |
| 119 | self.message().source() |
| 120 | } |
| 121 | |
| 122 | fn flags(&self) -> &MessageFlags { |
| 123 | self.message().flags() |
| 124 | } |
| 125 | |
| 126 | fn msgctxt(&self) -> &str { |
| 127 | self.message().msgctxt() |
| 128 | } |
| 129 | |
| 130 | fn msgid(&self) -> &str { |
| 131 | self.message().msgid() |
| 132 | } |
| 133 | |
| 134 | fn msgid_plural(&self) -> Result<&str, SingularPluralMismatchError> { |
| 135 | self.message().msgid_plural() |
| 136 | } |
| 137 | |
| 138 | fn msgstr(&self) -> Result<&str, SingularPluralMismatchError> { |
| 139 | self.message().msgstr() |
| 140 | } |
| 141 | |
| 142 | fn msgstr_plural(&self) -> Result<&Vec<String>, SingularPluralMismatchError> { |
| 143 | self.message().msgstr_plural() |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | impl<'a> MessageMutView for MessageMutProxy<'a> { |
| 148 | fn comments_mut(&mut self) -> &mut String { |
| 149 | &mut self.message_mut().comments |
| 150 | } |
| 151 | |
| 152 | fn source_mut(&mut self) -> &mut String { |
| 153 | &mut self.message_mut().source |
| 154 | } |
| 155 | |
| 156 | fn flags_mut(&mut self) -> &mut MessageFlags { |
| 157 | &mut self.message_mut().flags |
| 158 | } |
| 159 | |
| 160 | fn set_msgctxt(&mut self, msgctxt: String) { |
| 161 | let original_key = MessageKey::from(self.message()); |
| 162 | self.0.catalog.map.remove(&original_key); |
| 163 | self.message_mut().msgctxt = msgctxt; |
| 164 | let new_key = MessageKey::from(self.message()); |
| 165 | self.0.catalog.map.insert(new_key, self.0.index); |
| 166 | } |
| 167 | |
| 168 | fn set_msgid(&mut self, msgid: String) { |
| 169 | let original_key = MessageKey::from(self.message()); |
| 170 | self.0.catalog.map.remove(&original_key); |
| 171 | self.message_mut().msgctxt = msgid; |
| 172 | let new_key = MessageKey::from(self.message()); |
| 173 | self.0.catalog.map.insert(new_key, self.0.index); |
| 174 | } |
| 175 | |
| 176 | fn set_msgid_plural( |
| 177 | &mut self, |
| 178 | msgid_plural: String, |
| 179 | ) -> Result<(), SingularPluralMismatchError> { |
| 180 | if self.message_mut().is_plural() { |
| 181 | self.message_mut().msgid_plural = msgid_plural; |
| 182 | Ok(()) |
| 183 | } else { |
| 184 | Err(SingularPluralMismatchError) |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | fn set_msgstr(&mut self, msgstr: String) -> Result<(), SingularPluralMismatchError> { |
| 189 | if self.message_mut().is_plural() { |
| 190 | Err(SingularPluralMismatchError) |
| 191 | } else { |
| 192 | self.message_mut().msgstr = msgstr; |
| 193 | Ok(()) |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | fn msgstr_mut(&mut self) -> Result<&mut String, SingularPluralMismatchError> { |
| 198 | if self.message_mut().is_plural() { |
| 199 | Err(SingularPluralMismatchError) |
| 200 | } else { |
| 201 | Ok(&mut self.message_mut().msgstr) |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | fn msgstr_plural_mut(&mut self) -> Result<&mut Vec<String>, SingularPluralMismatchError> { |
| 206 | if self.message_mut().is_plural() { |
| 207 | Ok(&mut self.message_mut().msgstr_plural) |
| 208 | } else { |
| 209 | Err(SingularPluralMismatchError) |
| 210 | } |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | impl<'a> CatalogMessageMutView for MessageMutProxy<'a> { |
| 215 | fn delete(&mut self) { |
| 216 | let key: MessageKey = MessageKey::from(self.message()); |
| 217 | self.0.catalog.map.remove(&key); |
| 218 | self.0.catalog.messages[self.0.index] = None; |
| 219 | } |
| 220 | |
| 221 | fn detach(&mut self) -> Message { |
| 222 | let key: MessageKey = MessageKey::from(self.message()); |
| 223 | self.0.catalog.map.remove(&key); |
| 224 | self.0.catalog.messages[self.0.index].take().unwrap() |
| 225 | } |
| 226 | } |
| 227 | |