altium_format/api/generic/
container.rs1use crate::api::cfb::Block;
4use crate::records::pcb::PcbObjectId;
5use crate::types::ParameterCollection;
6
7use super::{BinaryRecord, GenericRecord};
8
9#[derive(Debug, Clone)]
13pub struct ParamsContainer {
14 source: String,
16 records: Vec<GenericRecord>,
18}
19
20impl ParamsContainer {
21 pub fn from_blocks(source: &str, blocks: &[Block]) -> Self {
23 let mut records = Vec::with_capacity(blocks.len());
24
25 for block in blocks {
26 if let Some(params) = block.as_params() {
27 records.push(GenericRecord::from_params(¶ms));
28 }
29 }
30
31 ParamsContainer {
32 source: source.to_string(),
33 records,
34 }
35 }
36
37 pub fn from_params_list(source: &str, params_list: Vec<ParameterCollection>) -> Self {
39 let records = params_list.iter().map(GenericRecord::from_params).collect();
40
41 ParamsContainer {
42 source: source.to_string(),
43 records,
44 }
45 }
46
47 pub fn source(&self) -> &str {
49 &self.source
50 }
51
52 pub fn len(&self) -> usize {
54 self.records.len()
55 }
56
57 pub fn is_empty(&self) -> bool {
59 self.records.is_empty()
60 }
61
62 pub fn get(&self, index: usize) -> Option<&GenericRecord> {
64 self.records.get(index)
65 }
66
67 pub fn get_mut(&mut self, index: usize) -> Option<&mut GenericRecord> {
69 self.records.get_mut(index)
70 }
71
72 pub fn iter(&self) -> impl Iterator<Item = &GenericRecord> {
74 self.records.iter()
75 }
76
77 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut GenericRecord> {
79 self.records.iter_mut()
80 }
81
82 pub fn filter_by_type(&self, record_id: i32) -> impl Iterator<Item = &GenericRecord> {
84 self.records
85 .iter()
86 .filter(move |r| r.record_id() == Some(record_id))
87 }
88
89 pub fn find<F>(&self, pred: F) -> Option<&GenericRecord>
91 where
92 F: Fn(&GenericRecord) -> bool,
93 {
94 self.records.iter().find(|r| pred(r))
95 }
96
97 pub fn find_all<F>(&self, pred: F) -> Vec<&GenericRecord>
99 where
100 F: Fn(&GenericRecord) -> bool,
101 {
102 self.records.iter().filter(|r| pred(r)).collect()
103 }
104
105 pub fn is_modified(&self) -> bool {
107 self.records.iter().any(|r| r.is_modified())
108 }
109
110 pub fn push(&mut self, record: GenericRecord) {
112 self.records.push(record);
113 }
114
115 pub fn remove(&mut self, index: usize) -> Option<GenericRecord> {
117 if index < self.records.len() {
118 Some(self.records.remove(index))
119 } else {
120 None
121 }
122 }
123
124 pub fn to_params_list(&self) -> Vec<ParameterCollection> {
126 self.records.iter().map(|r| r.to_params()).collect()
127 }
128}
129
130impl IntoIterator for ParamsContainer {
131 type Item = GenericRecord;
132 type IntoIter = std::vec::IntoIter<GenericRecord>;
133
134 fn into_iter(self) -> Self::IntoIter {
135 self.records.into_iter()
136 }
137}
138
139impl<'a> IntoIterator for &'a ParamsContainer {
140 type Item = &'a GenericRecord;
141 type IntoIter = std::slice::Iter<'a, GenericRecord>;
142
143 fn into_iter(self) -> Self::IntoIter {
144 self.records.iter()
145 }
146}
147
148#[derive(Debug, Clone)]
152pub struct BinaryContainer {
153 source: String,
155 records: Vec<BinaryRecord>,
157}
158
159impl BinaryContainer {
160 pub fn from_blocks(source: &str, blocks: &[Block]) -> Self {
164 let mut records = Vec::with_capacity(blocks.len());
165
166 for block in blocks {
167 if block.data.is_empty() {
168 continue;
169 }
170
171 let object_id = PcbObjectId::from_byte(block.data[0]);
172 records.push(BinaryRecord::from_binary(object_id, block.data.clone()));
173 }
174
175 BinaryContainer {
176 source: source.to_string(),
177 records,
178 }
179 }
180
181 pub fn new(source: &str) -> Self {
183 BinaryContainer {
184 source: source.to_string(),
185 records: Vec::new(),
186 }
187 }
188
189 pub fn source(&self) -> &str {
191 &self.source
192 }
193
194 pub fn len(&self) -> usize {
196 self.records.len()
197 }
198
199 pub fn is_empty(&self) -> bool {
201 self.records.is_empty()
202 }
203
204 pub fn get(&self, index: usize) -> Option<&BinaryRecord> {
206 self.records.get(index)
207 }
208
209 pub fn get_mut(&mut self, index: usize) -> Option<&mut BinaryRecord> {
211 self.records.get_mut(index)
212 }
213
214 pub fn iter(&self) -> impl Iterator<Item = &BinaryRecord> {
216 self.records.iter()
217 }
218
219 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut BinaryRecord> {
221 self.records.iter_mut()
222 }
223
224 pub fn filter_by_type(&self, object_id: PcbObjectId) -> impl Iterator<Item = &BinaryRecord> {
226 self.records
227 .iter()
228 .filter(move |r| r.object_id() == object_id)
229 }
230
231 pub fn is_modified(&self) -> bool {
233 self.records.iter().any(|r| r.is_modified())
234 }
235
236 pub fn push(&mut self, record: BinaryRecord) {
238 self.records.push(record);
239 }
240
241 pub fn remove(&mut self, index: usize) -> Option<BinaryRecord> {
243 if index < self.records.len() {
244 Some(self.records.remove(index))
245 } else {
246 None
247 }
248 }
249
250 pub fn to_binary(&self) -> Vec<Vec<u8>> {
252 self.records.iter().map(|r| r.to_binary()).collect()
253 }
254}
255
256impl IntoIterator for BinaryContainer {
257 type Item = BinaryRecord;
258 type IntoIter = std::vec::IntoIter<BinaryRecord>;
259
260 fn into_iter(self) -> Self::IntoIter {
261 self.records.into_iter()
262 }
263}
264
265impl<'a> IntoIterator for &'a BinaryContainer {
266 type Item = &'a BinaryRecord;
267 type IntoIter = std::slice::Iter<'a, BinaryRecord>;
268
269 fn into_iter(self) -> Self::IntoIter {
270 self.records.iter()
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277 use crate::api::cfb::Block;
278
279 #[test]
280 fn test_params_container_from_blocks() {
281 let blocks = vec![
282 Block {
283 offset: 0,
284 size: 20,
285 flags: 0,
286 data: b"|RECORD=1|NAME=A|\0".to_vec(),
287 },
288 Block {
289 offset: 24,
290 size: 20,
291 flags: 0,
292 data: b"|RECORD=2|NAME=B|\0".to_vec(),
293 },
294 ];
295
296 let container = ParamsContainer::from_blocks("/test", &blocks);
297 assert_eq!(container.len(), 2);
298 assert_eq!(container.get(0).unwrap().record_id(), Some(1));
299 assert_eq!(container.get(1).unwrap().record_id(), Some(2));
300 }
301
302 #[test]
303 fn test_filter_by_type() {
304 let params = vec![
305 ParameterCollection::from_string("|RECORD=1|"),
306 ParameterCollection::from_string("|RECORD=2|"),
307 ParameterCollection::from_string("|RECORD=1|"),
308 ];
309 let container = ParamsContainer::from_params_list("/test", params);
310
311 let record1s: Vec<_> = container.filter_by_type(1).collect();
312 assert_eq!(record1s.len(), 2);
313 }
314
315 #[test]
316 fn test_modification_tracking() {
317 let params = vec![ParameterCollection::from_string("|RECORD=1|NAME=Test|")];
318 let mut container = ParamsContainer::from_params_list("/test", params);
319
320 assert!(!container.is_modified());
321
322 container.get_mut(0).unwrap().set("NAME", "Modified");
323 assert!(container.is_modified());
324 }
325}